home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Game Programming Gurus / Tricks of the Windows Game Programming Gurus (SAMS)(2000).iso / Goodies / t3dlib1.cpp < prev    next >
C/C++ Source or Header  |  1999-08-31  |  168KB  |  6,120 lines

  1. // T3DLIB1.CPP - Game Engine Part I
  2.  
  3. // INCLUDES ///////////////////////////////////////////////
  4.  
  5. #define WIN32_LEAN_AND_MEAN  
  6.  
  7. // has the GUID library been included?
  8. //#ifndef INITGUID
  9. //#define INITGUID
  10. //#endif
  11.  
  12. #include <windows.h>   // include important windows stuff
  13. #include <windowsx.h> 
  14. #include <mmsystem.h>
  15. #include <iostream.h> // include important C/C++ stuff
  16. #include <conio.h>
  17. #include <stdlib.h>
  18. #include <malloc.h>
  19. #include <memory.h>
  20. #include <string.h>
  21. #include <stdarg.h>
  22. #include <stdio.h>
  23. #include <math.h>
  24. #include <io.h>
  25. #include <fcntl.h>
  26.  
  27. #include <ddraw.h>    // directX includes
  28. #include "T3DLIB1.H"
  29.  
  30. // DEFINES ////////////////////////////////////////////////
  31.  
  32. // TYPES //////////////////////////////////////////////////
  33.  
  34. // PROTOTYPES /////////////////////////////////////////////
  35.  
  36. // EXTERNALS /////////////////////////////////////////////
  37.  
  38. extern HWND main_window_handle; // save the window handle
  39. extern HINSTANCE main_instance; // save the instance
  40.  
  41. // GLOBALS ////////////////////////////////////////////////
  42.  
  43. FILE *fp_error                    = NULL; // general error file
  44.  
  45. // notice that interface 4.0 is used on a number of interfaces
  46. LPDIRECTDRAW4        lpdd         = NULL;  // dd object
  47. LPDIRECTDRAWSURFACE4 lpddsprimary = NULL;  // dd primary surface
  48. LPDIRECTDRAWSURFACE4 lpddsback    = NULL;  // dd back surface
  49. LPDIRECTDRAWPALETTE  lpddpal      = NULL;  // a pointer to the created dd palette
  50. LPDIRECTDRAWCLIPPER  lpddclipper  = NULL;   // dd clipper for back surface
  51. LPDIRECTDRAWCLIPPER  lpddclipperwin = NULL; // dd clipper for window
  52.  
  53. PALETTEENTRY         palette[MAX_COLORS_PALETTE];         // color palette
  54. PALETTEENTRY         save_palette[MAX_COLORS_PALETTE];    // used to save palettes
  55. DDSURFACEDESC2       ddsd;                 // a direct draw surface description struct
  56. DDBLTFX              ddbltfx;              // used to fill
  57. DDSCAPS2             ddscaps;              // a direct draw surface capabilities struct
  58. HRESULT              ddrval;               // result back from dd calls
  59. UCHAR                *primary_buffer = NULL; // primary video buffer
  60. UCHAR                *back_buffer    = NULL; // secondary back buffer
  61. int                  primary_lpitch  = 0;    // memory line pitch for primary buffer
  62. int                  back_lpitch     = 0;    // memory line pitch for back buffer
  63. BITMAP_FILE          bitmap8bit;             // a 8 bit bitmap file
  64. BITMAP_FILE          bitmap16bit;            // a 16 bit bitmap file
  65. BITMAP_FILE          bitmap24bit;            // a 24 bit bitmap file
  66.  
  67. DWORD                start_clock_count = 0;     // used for timing
  68. int                  windowed_mode     = FALSE; // tracks if dd is windowed or not
  69.  
  70. // these defined the general clipping rectangle
  71. int min_clip_x = 0,                             // clipping rectangle 
  72.     max_clip_x = (SCREEN_WIDTH-1),
  73.     min_clip_y = 0,
  74.     max_clip_y = (SCREEN_HEIGHT-1);
  75.  
  76. // these are overwritten globally by DDraw_Init()
  77. int screen_width    = SCREEN_WIDTH,            // width of screen
  78.     screen_height   = SCREEN_HEIGHT,           // height of screen
  79.     screen_bpp      = SCREEN_BPP,              // bits per pixel
  80.     screen_windowed = 0;                       // is this a windowed app?    
  81.  
  82. int dd_pixel_format = DD_PIXEL_FORMAT565;  // default pixel format
  83.  
  84. int window_client_x0   = 0;   // used to track the starting (x,y) client area for
  85. int window_client_y0   = 0;   // for windowed mode directdraw operations
  86.  
  87. // storage for our lookup tables
  88. float cos_look[360];
  89. float sin_look[360];
  90.  
  91. // FUNCTIONS //////////////////////////////////////////////
  92.  
  93. inline void Mem_Set_WORD(void *dest, USHORT data, int count)
  94. {
  95. // this function fills or sets unsigned 16-bit aligned memory
  96. // count is number of words
  97.  
  98. _asm 
  99.     { 
  100.     mov edi, dest   ; edi points to destination memory
  101.     mov ecx, count  ; number of 16-bit words to move
  102.     mov ax,  data   ; 16-bit data
  103.     rep stosw       ; move data
  104.     } // end asm
  105.  
  106. } // end Mem_Set_WORD
  107.  
  108. ///////////////////////////////////////////////////////////
  109.  
  110. inline void Mem_Set_QUAD(void *dest, UINT data, int count)
  111. {
  112. // this function fills or sets unsigned 32-bit aligned memory
  113. // count is number of quads
  114.  
  115. _asm 
  116.     { 
  117.     mov edi, dest   ; edi points to destination memory
  118.     mov ecx, count  ; number of 32-bit words to move
  119.     mov eax, data   ; 32-bit data
  120.     rep stosd       ; move data
  121.     } // end asm
  122.  
  123. } // end Mem_Set_QUAD
  124.  
  125. //////////////////////////////////////////////////////////
  126.  
  127. int Create_BOB(BOB_PTR bob,           // the bob to create
  128.                int x, int y,          // initial posiiton
  129.                int width, int height, // size of bob
  130.                int num_frames,        // number of frames
  131.                int attr,              // attrs
  132.                int mem_flags,         // memory flags in DD format
  133.                USHORT color_key_value, // default color key
  134.                int bpp)                // bits per pixel
  135.  
  136. {
  137. // Create the BOB object, note that all BOBs 
  138. // are created as offscreen surfaces in VRAM as the
  139. // default, if you want to use system memory then
  140. // set flags equal to:
  141. // DDSCAPS_SYSTEMMEMORY 
  142. // for video memory you can create either local VRAM surfaces or AGP 
  143. // surfaces via the second set of constants shown below in the regular expression
  144. // DDSCAPS_VIDEOMEMORY | (DDSCAPS_NONLOCALVIDMEM | DDSCAPS_LOCALVIDMEM ) 
  145.  
  146.  
  147. DDSURFACEDESC2 ddsd; // used to create surface
  148. int index;           // looping var
  149.  
  150. // set state and attributes of BOB
  151. bob->state          = BOB_STATE_ALIVE;
  152. bob->attr           = attr;
  153. bob->anim_state     = 0;
  154. bob->counter_1      = 0;     
  155. bob->counter_2      = 0;
  156. bob->max_count_1    = 0;
  157. bob->max_count_2    = 0;
  158.  
  159. bob->curr_frame     = 0;
  160. bob->num_frames     = num_frames;
  161. bob->bpp            = bpp;
  162. bob->curr_animation = 0;
  163. bob->anim_counter   = 0;
  164. bob->anim_index     = 0;
  165. bob->anim_count_max = 0; 
  166. bob->x              = x;
  167. bob->y              = y;
  168. bob->xv             = 0;
  169. bob->yv             = 0;
  170.  
  171. // set dimensions of the new bitmap surface
  172. bob->width  = width;
  173. bob->height = height;
  174.  
  175. // set all images to null
  176. for (index=0; index<MAX_BOB_FRAMES; index++)
  177.     bob->images[index] = NULL;
  178.  
  179. // set all animations to null
  180. for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  181.     bob->animations[index] = NULL;
  182.  
  183. // make sure surface width is a multiple of 8, dd likes that
  184. bob->width_fill = ((width%8!=0) ? (8-width%8) : 0);
  185. Write_Error("\nCreate BOB %d",bob->width_fill);
  186.  
  187. // now create each surface
  188. for (index=0; index<bob->num_frames; index++)
  189.     {
  190.     // set to access caps, width, and height
  191.     memset(&ddsd,0,sizeof(ddsd));
  192.     ddsd.dwSize  = sizeof(ddsd);
  193.     ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  194.  
  195.     ddsd.dwWidth  = bob->width + bob->width_fill;
  196.     ddsd.dwHeight = bob->height;
  197.  
  198.     // set surface to offscreen plain
  199.     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  200.  
  201.     // create the surfaces, return failure if problem
  202.     if (FAILED(lpdd->CreateSurface(&ddsd,&(bob->images[index]),NULL)))
  203.         return(0);
  204.  
  205.     // set color key to default color 000
  206.     // note that if this is a 8bit bob then palette index 0 will be 
  207.     // transparent by default
  208.     // note that if this is a 16bit bob then RGB value 000 will be 
  209.     // transparent
  210.     DDCOLORKEY color_key; // used to set color key
  211.     color_key.dwColorSpaceLowValue  = color_key_value;
  212.     color_key.dwColorSpaceHighValue = color_key_value;
  213.  
  214.     // now set the color key for source blitting
  215.     (bob->images[index])->SetColorKey(DDCKEY_SRCBLT, &color_key);
  216.     
  217.     } // end for index
  218.  
  219. // return success
  220. return(1);
  221.  
  222. } // end Create_BOB
  223.  
  224. ///////////////////////////////////////////////////////////
  225.  
  226. int Clone_BOB(BOB_PTR source, BOB_PTR dest)
  227. {
  228. // this function clones a BOB and updates the attr var to reflect that
  229. // the BOB is a clone and not real, this is used later in the destroy
  230. // function so a clone doesn't destroy the memory of a real bob
  231.  
  232. if ((source && dest) && (source!=dest))
  233.    {
  234.    // copy the bob data
  235.    memcpy(dest,source, sizeof(BOB));
  236.  
  237.    // set the clone attribute
  238.    dest->attr |= BOB_ATTR_CLONE;
  239.  
  240.    } // end if
  241.  
  242. else
  243.     return(0);
  244.  
  245. // return success
  246. return(1);
  247.  
  248. } // end Clone_BOB
  249.  
  250. ///////////////////////////////////////////////////////////
  251.  
  252. int Destroy_BOB(BOB_PTR bob)
  253. {
  254. // destroy the BOB, tests if this is a real bob or a clone
  255. // if real then release all the memory, otherwise, just resets
  256. // the pointers to null
  257.  
  258. int index; // looping var
  259.  
  260. // is this bob valid
  261. if (!bob)
  262.     return(0);
  263.  
  264. // test if this is a clone
  265. if (bob->attr && BOB_ATTR_CLONE)
  266.     {
  267.     // null link all surfaces
  268.     for (index=0; index<MAX_BOB_FRAMES; index++)
  269.         if (bob->images[index])
  270.             bob->images[index]=NULL;
  271.  
  272.     // release memory for animation sequences 
  273.     for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  274.         if (bob->animations[index])
  275.             bob->animations[index]=NULL;
  276.  
  277.     } // end if
  278. else
  279.     {
  280.     // destroy each bitmap surface
  281.     for (index=0; index<MAX_BOB_FRAMES; index++)
  282.         if (bob->images[index])
  283.             (bob->images[index])->Release();
  284.  
  285.     // release memory for animation sequences 
  286.     for (index=0; index<MAX_BOB_ANIMATIONS; index++)
  287.         if (bob->animations[index])
  288.             free(bob->animations[index]);
  289.  
  290.     } // end else not clone
  291.  
  292. // return success
  293. return(1);
  294.  
  295. } // end Destroy_BOB
  296.  
  297. ///////////////////////////////////////////////////////////
  298.  
  299. int Draw_BOB(BOB_PTR bob,               // bob to draw
  300.              LPDIRECTDRAWSURFACE4 dest) // surface to draw the bob on
  301. {
  302. // draw a bob at the x,y defined in the BOB
  303. // on the destination surface defined in dest
  304.  
  305. RECT dest_rect,   // the destination rectangle
  306.      source_rect; // the source rectangle                             
  307.  
  308. // is this a valid bob
  309. if (!bob)
  310.     return(0);
  311.  
  312. // is bob visible
  313. if (!(bob->attr & BOB_ATTR_VISIBLE))
  314.    return(1);
  315.  
  316. // fill in the destination rect
  317. dest_rect.left   = bob->x;
  318. dest_rect.top    = bob->y;
  319. dest_rect.right  = bob->x+bob->width;
  320. dest_rect.bottom = bob->y+bob->height;
  321.  
  322. // fill in the source rect
  323. source_rect.left    = 0;
  324. source_rect.top     = 0;
  325. source_rect.right   = bob->width;
  326. source_rect.bottom  = bob->height;
  327.  
  328. // blt to destination surface
  329. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  330.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  331.           NULL)))
  332.     return(0);
  333.  
  334. // return success
  335. return(1);
  336. } // end Draw_BOB
  337.  
  338. ///////////////////////////////////////////////////////////
  339.  
  340. int Draw_Scaled_BOB(BOB_PTR bob, int swidth, int sheight,  // bob and new dimensions
  341.                     LPDIRECTDRAWSURFACE4 dest) // surface to draw the bob on)
  342. {
  343. // this function draws a scaled bob to the size swidth, sheight
  344.  
  345. RECT dest_rect,   // the destination rectangle
  346.      source_rect; // the source rectangle                             
  347.  
  348. // is this a valid bob
  349. if (!bob)
  350.     return(0);
  351.  
  352. // is bob visible
  353. if (!(bob->attr & BOB_ATTR_VISIBLE))
  354.    return(1);
  355.  
  356. // fill in the destination rect
  357. dest_rect.left   = bob->x;
  358. dest_rect.top    = bob->y;
  359. dest_rect.right  = bob->x+swidth;
  360. dest_rect.bottom = bob->y+sheight;
  361.  
  362. // fill in the source rect
  363. source_rect.left    = 0;
  364. source_rect.top     = 0;
  365. source_rect.right   = bob->width;
  366. source_rect.bottom  = bob->height;
  367.  
  368. // blt to destination surface
  369. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  370.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  371.           NULL)))
  372.     return(0);
  373.  
  374. // return success
  375. return(1);
  376. } // end Draw_Scaled_BOB
  377.  
  378. ////////////////////////////////////////////////////
  379.  
  380. int Draw_BOB16(BOB_PTR bob,             // bob to draw
  381.              LPDIRECTDRAWSURFACE4 dest) // surface to draw the bob on
  382. {
  383. // draw a bob at the x,y defined in the BOB
  384. // on the destination surface defined in dest
  385.  
  386. RECT dest_rect,   // the destination rectangle
  387.      source_rect; // the source rectangle                             
  388.  
  389. // is this a valid bob
  390. if (!bob)
  391.     return(0);
  392.  
  393. // is bob visible
  394. if (!(bob->attr & BOB_ATTR_VISIBLE))
  395.    return(1);
  396.  
  397. // fill in the destination rect
  398. dest_rect.left   = bob->x;
  399. dest_rect.top    = bob->y;
  400. dest_rect.right  = bob->x+bob->width;
  401. dest_rect.bottom = bob->y+bob->height;
  402.  
  403. // fill in the source rect
  404. source_rect.left    = 0;
  405. source_rect.top     = 0;
  406. source_rect.right   = bob->width;
  407. source_rect.bottom  = bob->height;
  408.  
  409. // blt to destination surface
  410. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  411.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  412.           NULL)))
  413.     return(0);
  414.  
  415. // return success
  416. return(1);
  417. } // end Draw_BOB16
  418.  
  419. ///////////////////////////////////////////////////////////
  420.  
  421. int Draw_Scaled_BOB16(BOB_PTR bob, int swidth, int sheight,  // bob and new dimensions
  422.                     LPDIRECTDRAWSURFACE4 dest) // surface to draw the bob on)
  423. {
  424. // this function draws a scaled bob to the size swidth, sheight
  425.  
  426. RECT dest_rect,   // the destination rectangle
  427.      source_rect; // the source rectangle                             
  428.  
  429. // is this a valid bob
  430. if (!bob)
  431.     return(0);
  432.  
  433. // is bob visible
  434. if (!(bob->attr & BOB_ATTR_VISIBLE))
  435.    return(1);
  436.  
  437. // fill in the destination rect
  438. dest_rect.left   = bob->x;
  439. dest_rect.top    = bob->y;
  440. dest_rect.right  = bob->x+swidth;
  441. dest_rect.bottom = bob->y+sheight;
  442.  
  443. // fill in the source rect
  444. source_rect.left    = 0;
  445. source_rect.top     = 0;
  446. source_rect.right   = bob->width;
  447. source_rect.bottom  = bob->height;
  448.  
  449. // blt to destination surface
  450. if (FAILED(dest->Blt(&dest_rect, bob->images[bob->curr_frame],
  451.           &source_rect,(DDBLT_WAIT | DDBLT_KEYSRC),
  452.           NULL)))
  453.     return(0);
  454.  
  455. // return success
  456. return(1);
  457. } // end Draw_Scaled_BOB16
  458.  
  459. ///////////////////////////////////////////////////////////
  460.  
  461. ///////////////////////////////////////////////////////////
  462.  
  463. int Load_Frame_BOB(BOB_PTR bob, // bob to load with data
  464.                    BITMAP_FILE_PTR bitmap, // bitmap to scan image data from
  465.                    int frame,       // frame to load
  466.                    int cx,int cy,   // cell or absolute pos. to scan image from
  467.                    int mode)        // if 0 then cx,cy is cell position, else 
  468.                                     // cx,cy are absolute coords
  469. {
  470. // this function extracts a bitmap out of a bitmap file
  471.  
  472. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  473.  
  474. // is this a valid bob
  475. if (!bob)
  476.    return(0);
  477.  
  478. UCHAR *source_ptr,   // working pointers
  479.       *dest_ptr;
  480.  
  481. // test the mode of extraction, cell based or absolute
  482. if (mode==BITMAP_EXTRACT_MODE_CELL)
  483.    {
  484.    // re-compute x,y
  485.    cx = cx*(bob->width+1) + 1;
  486.    cy = cy*(bob->height+1) + 1;
  487.    } // end if
  488.  
  489. // extract bitmap data
  490. source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  491.  
  492. // get the addr to destination surface memory
  493.  
  494. // set size of the structure
  495. ddsd.dwSize = sizeof(ddsd);
  496.  
  497. // lock the display surface
  498. (bob->images[frame])->Lock(NULL,
  499.                            &ddsd,
  500.                            DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  501.                            NULL);
  502.  
  503. // assign a pointer to the memory surface for manipulation
  504. dest_ptr = (UCHAR *)ddsd.lpSurface;
  505.  
  506. // iterate thru each scanline and copy bitmap
  507. for (int index_y=0; index_y<bob->height; index_y++)
  508.     {
  509.     // copy next line of data to destination
  510.     memcpy(dest_ptr, source_ptr,bob->width);
  511.  
  512.     // advance pointers
  513.     dest_ptr   += (bob->width+bob->width_fill);
  514.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  515.     } // end for index_y
  516.  
  517. // unlock the surface 
  518. (bob->images[frame])->Unlock(NULL);
  519.  
  520. // set state to loaded
  521. bob->attr |= BOB_ATTR_LOADED;
  522.  
  523. // return success
  524. return(1);
  525.  
  526. } // end Load_Frame_BOB
  527.  
  528. ///////////////////////////////////////////////////////////////
  529.  
  530. int Load_Frame_BOB16(BOB_PTR bob, // bob to load with data
  531.                      BITMAP_FILE_PTR bitmap, // bitmap to scan image data from
  532.                      int frame,       // frame to load
  533.                      int cx,int cy,   // cell or absolute pos. to scan image from
  534.                      int mode)        // if 0 then cx,cy is cell position, else 
  535.                                     // cx,cy are absolute coords
  536. {
  537. // this function extracts a 16-bit bitmap out of a 16-bit bitmap file
  538.  
  539. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  540.  
  541. // is this a valid bob
  542. if (!bob)
  543.    return(0);
  544.  
  545. USHORT *source_ptr,   // working pointers
  546.        *dest_ptr;
  547.  
  548. // test the mode of extraction, cell based or absolute
  549. if (mode==BITMAP_EXTRACT_MODE_CELL)
  550.    {
  551.    // re-compute x,y
  552.    cx = cx*(bob->width+1) + 1;
  553.    cy = cy*(bob->height+1) + 1;
  554.    } // end if
  555.  
  556. // extract bitmap data
  557. source_ptr = (USHORT *)bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  558.  
  559. // get the addr to destination surface memory
  560.  
  561. // set size of the structure
  562. ddsd.dwSize = sizeof(ddsd);
  563.  
  564. // lock the display surface
  565. (bob->images[frame])->Lock(NULL,
  566.                            &ddsd,
  567.                            DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  568.                            NULL);
  569.  
  570. // assign a pointer to the memory surface for manipulation
  571. dest_ptr = (USHORT *)ddsd.lpSurface;
  572.  
  573. int bytes_per_line = (bob->width+bob->width_fill)*2;
  574.  
  575. // iterate thru each scanline and copy bitmap
  576. for (int index_y=0; index_y<bob->height; index_y++)
  577.     {
  578.     // copy next line of data to destination
  579.     memcpy(dest_ptr, source_ptr,bytes_per_line);
  580.  
  581.     // advance pointers
  582.     dest_ptr   += (bob->width+bob->width_fill);
  583.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  584.     } // end for index_y
  585.  
  586. // unlock the surface 
  587. (bob->images[frame])->Unlock(NULL);
  588.  
  589. // set state to loaded
  590. bob->attr |= BOB_ATTR_LOADED;
  591.  
  592. // return success
  593. return(1);
  594.  
  595. } // end Load_Frame_BOB16
  596.  
  597. ///////////////////////////////////////////////////////////
  598.  
  599. int Animate_BOB(BOB_PTR bob)
  600. {
  601. // this function animates a bob, basically it takes a look at
  602. // the attributes of the bob and determines if the bob is 
  603. // a single frame, multiframe, or multi animation, updates
  604. // the counters and frames appropriately
  605.  
  606. // is this a valid bob
  607. if (!bob)
  608.    return(0);
  609.  
  610. // test the level of animation
  611. if (bob->attr & BOB_ATTR_SINGLE_FRAME)
  612.     {
  613.     // current frame always = 0
  614.     bob->curr_frame = 0;
  615.     return(1);
  616.     } // end if
  617. else
  618. if (bob->attr & BOB_ATTR_MULTI_FRAME)
  619.    {
  620.    // update the counter and test if its time to increment frame
  621.    if (++bob->anim_counter >= bob->anim_count_max)
  622.       {
  623.       // reset counter
  624.       bob->anim_counter = 0;
  625.  
  626.       // move to next frame
  627.       if (++bob->curr_frame >= bob->num_frames)
  628.          bob->curr_frame = 0;
  629.  
  630.       } // end if
  631.   
  632.    } // end elseif
  633. else
  634. if (bob->attr & BOB_ATTR_MULTI_ANIM)
  635.    {
  636.    // this is the most complex of the animations it must look up the
  637.    // next frame in the animation sequence
  638.  
  639.    // first test if its time to animate
  640.    if (++bob->anim_counter >= bob->anim_count_max)
  641.       {
  642.       // reset counter
  643.       bob->anim_counter = 0;
  644.  
  645.       // increment the animation frame index
  646.       bob->anim_index++;
  647.       
  648.       // extract the next frame from animation list 
  649.       bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  650.      
  651.       // is this and end sequence flag -1
  652.       if (bob->curr_frame == -1)
  653.          {
  654.          // test if this is a single shot animation
  655.          if (bob->attr & BOB_ATTR_ANIM_ONE_SHOT)
  656.             {
  657.             // set animation state message to done
  658.             bob->anim_state = BOB_STATE_ANIM_DONE;
  659.             
  660.             // reset frame back one
  661.             bob->anim_index--;
  662.  
  663.             // extract animation frame
  664.             bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];    
  665.  
  666.             } // end if
  667.         else
  668.            {
  669.            // reset animation index
  670.            bob->anim_index = 0;
  671.  
  672.            // extract first animation frame
  673.            bob->curr_frame = bob->animations[bob->curr_animation][bob->anim_index];
  674.            } // end else
  675.  
  676.          }  // end if
  677.       
  678.       } // end if
  679.  
  680.    } // end elseif
  681.  
  682. // return success
  683. return(1);
  684.  
  685. } // end Amimate_BOB
  686.  
  687. ///////////////////////////////////////////////////////////
  688.  
  689. int Scroll_BOB(void)
  690. {
  691. // this function scrolls a bob 
  692. // not implemented
  693.  
  694. // return success
  695. return(1);
  696. } // end Scroll_BOB
  697.  
  698. ///////////////////////////////////////////////////////////
  699.  
  700. int Move_BOB(BOB_PTR bob)
  701. {
  702. // this function moves the bob based on its current velocity
  703. // also, the function test for various motion attributes of the'
  704. // bob and takes the appropriate actions
  705.    
  706.  
  707. // is this a valid bob
  708. if (!bob)
  709.    return(0);
  710.  
  711. // translate the bob
  712. bob->x+=bob->xv;
  713. bob->y+=bob->yv;
  714.  
  715. // test for wrap around
  716. if (bob->attr & BOB_ATTR_WRAPAROUND)
  717.    {
  718.    // test x extents first
  719.    if (bob->x > max_clip_x)
  720.        bob->x = min_clip_x - bob->width;
  721.    else
  722.    if (bob->x < min_clip_x-bob->width)
  723.        bob->x = max_clip_x;
  724.    
  725.    // now y extents
  726.    if (bob->x > max_clip_x)
  727.        bob->x = min_clip_x - bob->width;
  728.    else
  729.    if (bob->x < min_clip_x-bob->width)
  730.        bob->x = max_clip_x;
  731.  
  732.    } // end if
  733. else
  734. // test for bounce
  735. if (bob->attr & BOB_ATTR_BOUNCE)
  736.    {
  737.    // test x extents first
  738.    if ((bob->x > max_clip_x - bob->width) || (bob->x < min_clip_x) )
  739.        bob->xv = -bob->xv;
  740.     
  741.    // now y extents 
  742.    if ((bob->y > max_clip_y - bob->height) || (bob->y < min_clip_y) )
  743.        bob->yv = -bob->yv;
  744.  
  745.    } // end if
  746.  
  747. // return success
  748. return(1);
  749. } // end Move_BOB
  750.  
  751. ///////////////////////////////////////////////////////////
  752.  
  753. int Load_Animation_BOB(BOB_PTR bob, 
  754.                        int anim_index, 
  755.                        int num_frames, 
  756.                        int *sequence)
  757. {
  758. // this function load an animation sequence for a bob
  759. // the sequence consists of frame indices, the function
  760. // will append a -1 to the end of the list so the display
  761. // software knows when to restart the animation sequence
  762.  
  763. // is this bob valid
  764. if (!bob)
  765.    return(0);
  766.  
  767. // allocate memory for bob animation
  768. if (!(bob->animations[anim_index] = (int *)malloc((num_frames+1)*sizeof(int))))
  769.    return(0);
  770.  
  771. // load data into 
  772. for (int index=0; index<num_frames; index++)
  773.     bob->animations[anim_index][index] = sequence[index];
  774.  
  775. // set the end of the list to a -1
  776. bob->animations[anim_index][index] = -1;
  777.  
  778. // return success
  779. return(1);
  780.  
  781. } // end Load_Animation_BOB
  782.  
  783. ///////////////////////////////////////////////////////////
  784.  
  785. int Set_Pos_BOB(BOB_PTR bob, int x, int y)
  786. {
  787. // this functions sets the postion of a bob
  788.  
  789. // is this a valid bob
  790. if (!bob)
  791.    return(0);
  792.  
  793. // set positin
  794. bob->x = x;
  795. bob->y = y;
  796.  
  797. // return success
  798. return(1);
  799. } // end Set_Pos_BOB
  800.  
  801. ///////////////////////////////////////////////////////////
  802.  
  803. int Set_Anim_Speed_BOB(BOB_PTR bob,int speed)
  804. {
  805. // this function simply sets the animation speed of a bob
  806.     
  807. // is this a valid bob
  808. if (!bob)
  809.    return(0);
  810.  
  811. // set speed
  812. bob->anim_count_max = speed;
  813.  
  814. // return success
  815. return(1);
  816.  
  817. } // end Set_Anim_Speed
  818.  
  819. ///////////////////////////////////////////////////////////
  820.  
  821. int Set_Animation_BOB(BOB_PTR bob, int anim_index)
  822. {
  823. // this function sets the animation to play
  824.  
  825. // is this a valid bob
  826. if (!bob)
  827.    return(0);
  828.  
  829. // set the animation index
  830. bob->curr_animation = anim_index;
  831.  
  832. // reset animation 
  833. bob->anim_index = 0;
  834.  
  835. // return success
  836. return(1);
  837.  
  838. } // end Set_Animation_BOB
  839.  
  840. ///////////////////////////////////////////////////////////
  841.  
  842. int Set_Vel_BOB(BOB_PTR bob,int xv, int yv)
  843. {
  844. // this function sets the velocity of a bob
  845.  
  846. // is this a valid bob
  847. if (!bob)
  848.    return(0);
  849.  
  850. // set velocity
  851. bob->xv = xv;
  852. bob->yv = yv;
  853.  
  854. // return success
  855. return(1);
  856. } // end Set_Vel_BOB
  857.  
  858. ///////////////////////////////////////////////////////////
  859.  
  860. int Hide_BOB(BOB_PTR bob)
  861. {
  862. // this functions hides bob 
  863.  
  864. // is this a valid bob
  865. if (!bob)
  866.    return(0);
  867.  
  868. // reset the visibility bit
  869. RESET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  870.  
  871. // return success
  872. return(1);
  873. } // end Hide_BOB
  874.  
  875. ///////////////////////////////////////////////////////////
  876.  
  877. int Show_BOB(BOB_PTR bob)
  878. {
  879. // this function shows a bob
  880.  
  881. // is this a valid bob
  882. if (!bob)
  883.    return(0);
  884.  
  885. // set the visibility bit
  886. SET_BIT(bob->attr, BOB_ATTR_VISIBLE);
  887.  
  888. // return success
  889. return(1);
  890. } // end Show_BOB
  891.  
  892. ///////////////////////////////////////////////////////////
  893.  
  894. int Collision_BOBS(BOB_PTR bob1, BOB_PTR bob2)
  895. {
  896. // are these a valid bobs
  897. if (!bob1 || !bob2)
  898.    return(0);
  899.  
  900. // get the radi of each rect
  901. int width1  = (bob1->width>>1) - (bob1->width>>3);
  902. int height1 = (bob1->height>>1) - (bob1->height>>3);
  903.  
  904. int width2  = (bob2->width>>1) - (bob2->width>>3);
  905. int height2 = (bob2->height>>1) - (bob2->height>>3);
  906.  
  907. // compute center of each rect
  908. int cx1 = bob1->x + width1;
  909. int cy1 = bob1->y + height1;
  910.  
  911. int cx2 = bob2->x + width2;
  912. int cy2 = bob2->y + height2;
  913.  
  914. // compute deltas
  915. int dx = abs(cx2 - cx1);
  916. int dy = abs(cy2 - cy1);
  917.  
  918. // test if rects overlap
  919. if (dx < (width1+width2) && dy < (height1+height2))
  920.    return(1);
  921. else
  922. // else no collision
  923. return(0);
  924.  
  925. } // end Collision_BOBS
  926.  
  927. //////////////////////////////////////////////////////////
  928.  
  929. int DDraw_Init(int width, int height, int bpp, int windowed)
  930. {
  931. // this function initializes directdraw
  932. int index; // looping variable
  933.  
  934. LPDIRECTDRAW lpdd_temp = NULL; // used to get directdraw1
  935.  
  936. // create IDirectDrawdirectdraw interface 1.0 object and test for error
  937. if (FAILED(DirectDrawCreate(NULL,&lpdd_temp,NULL)))
  938.    return(0);
  939.  
  940. // now query for IDirectDraw4
  941. if (FAILED(lpdd_temp->QueryInterface(IID_IDirectDraw4,
  942.                                (LPVOID *)&lpdd)))
  943.    return(0);
  944.  
  945.  
  946.  
  947.  
  948. // based on windowed or fullscreen set coorperation level
  949. if (windowed)
  950.    {
  951.    // set cooperation level to windowed mode 
  952.    if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,DDSCL_NORMAL)))
  953.        return(0);
  954.  
  955.    } // end if
  956. else
  957.    {
  958.    // set cooperation level to fullscreen mode 
  959.    if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,
  960.               DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN | 
  961.               DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT)))
  962.        return(0);
  963.  
  964.    // set the display mode
  965.    if (FAILED(lpdd->SetDisplayMode(width,height,bpp,0,0)))
  966.       return(0);
  967.  
  968.    } // end else
  969.  
  970. // set globals
  971. screen_height   = height;
  972. screen_width    = width;
  973. screen_bpp      = bpp;
  974. screen_windowed = windowed;
  975.  
  976. // Create the primary surface
  977. memset(&ddsd,0,sizeof(ddsd));
  978. ddsd.dwSize = sizeof(ddsd);
  979.  
  980. // we need to let dd know that we want a complex 
  981. // flippable surface structure, set flags for that
  982. if (!screen_windowed)
  983.    {
  984.    // fullscreen mode
  985.    ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
  986.    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
  987.    
  988.    // set the backbuffer count to 0 for windowed mode
  989.    // 1 for fullscreen mode, 2 for triple buffering
  990.    ddsd.dwBackBufferCount = 1;
  991.    } // end if
  992. else
  993.    {
  994.    // windowed mode
  995.    ddsd.dwFlags = DDSD_CAPS;
  996.    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  997.  
  998.    // set the backbuffer count to 0 for windowed mode
  999.    // 1 for fullscreen mode, 2 for triple buffering
  1000.    ddsd.dwBackBufferCount = 0;
  1001.    } // end else
  1002.  
  1003. // create the primary surface
  1004. lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL);
  1005.  
  1006. // get the pixel format of the primary surface
  1007. DDPIXELFORMAT ddpf; // used to get pixel format
  1008.  
  1009. // initialize structure
  1010. DDRAW_INIT_STRUCT(ddpf);
  1011.  
  1012. // query the format from primary surface
  1013. lpddsprimary->GetPixelFormat(&ddpf);
  1014.  
  1015. // based on masks determine if system is 5.6.5 or 5.5.5
  1016. //RGB Masks for 5.6.5 mode
  1017. //DDPF_RGB  16 R: 0x0000F800  
  1018. //             G: 0x000007E0  
  1019. //             B: 0x0000001F  
  1020.  
  1021. //RGB Masks for 5.5.5 mode
  1022. //DDPF_RGB  16 R: 0x00007C00  
  1023. //             G: 0x000003E0  
  1024. //             B: 0x0000001F  
  1025. // test for 6 bit green mask)
  1026. //if (ddpf.dwGBitMask == 0x000007E0)
  1027. //   dd_pixel_format = DD_PIXEL_FORMAT565;
  1028.  
  1029. // use number of bits, better method
  1030. dd_pixel_format = ddpf.dwRGBBitCount;
  1031.  
  1032. Write_Error("\npixel format = %d",dd_pixel_format);
  1033.  
  1034.  
  1035. // only need a backbuffer for fullscreen modes
  1036. if (!screen_windowed)
  1037.    {
  1038.    // query for the backbuffer i.e the secondary surface
  1039.    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
  1040.  
  1041.    if (FAILED(lpddsprimary->GetAttachedSurface(&ddscaps,&lpddsback)))
  1042.       return(0);
  1043.  
  1044.    } // end if
  1045. else
  1046.    {
  1047.    // must be windowed, so create a double buffer that will be blitted
  1048.    // rather than flipped as in full screen mode
  1049.    lpddsback = DDraw_Create_Surface(width, height); // int mem_flags, USHORT color_key_flag);
  1050.  
  1051.    } // end else
  1052.  
  1053. // create a palette only if 8bit mode
  1054. if (screen_bpp==DD_PIXEL_FORMAT8)
  1055. {
  1056. // create and attach palette
  1057. // clear all entries, defensive programming
  1058. memset(palette,0,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  1059.  
  1060. // load a pre-made "good" palette off disk
  1061. Load_Palette_From_File(DEFAULT_PALETTE_FILE, palette);
  1062.  
  1063. // load and attach the palette, test for windowed mode
  1064. if (screen_windowed)
  1065.    {
  1066.    // in windowed mode, so the first 10 and last 10 entries have
  1067.    // to be slightly modified as does the call to createpalette
  1068.    // reset the peFlags bit to PC_EXPLICIT for the "windows" colors
  1069.    for (index=0; index < 10; index++)
  1070.        palette[index].peFlags = palette[index+246].peFlags = PC_EXPLICIT;         
  1071.  
  1072.    // now create the palette object, but disable access to all 256 entries
  1073.    if (FAILED(lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE,
  1074.                                   palette,&lpddpal,NULL)))
  1075.    return(0);
  1076.  
  1077.    } // end 
  1078. else
  1079.    {
  1080.    // in fullscreen mode, so simple create the palette with the default palette
  1081.    // and fill in all 256 entries
  1082.    if (FAILED(lpdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256,
  1083.                                   palette,&lpddpal,NULL)))
  1084.       return(0);
  1085.  
  1086.    } // end if
  1087.  
  1088. // now attach the palette to the primary surface
  1089. if (FAILED(lpddsprimary->SetPalette(lpddpal)))
  1090.    return(0);
  1091.  
  1092. } // end if attach palette for 8bit mode
  1093.  
  1094. // clear out both primary and secondary surfaces
  1095. if (screen_windowed)
  1096.    {
  1097.    // only clear backbuffer
  1098.    DDraw_Fill_Surface(lpddsback,0);
  1099.    } // end if
  1100. else
  1101.    {
  1102.    // fullscreen, simply clear everything
  1103.    DDraw_Fill_Surface(lpddsprimary,0);
  1104.    DDraw_Fill_Surface(lpddsback,0);
  1105.    } // end else
  1106.  
  1107. // set software algorithmic clipping region
  1108. min_clip_x = 0;
  1109. max_clip_x = screen_width - 1;
  1110. min_clip_y = 0;
  1111. max_clip_y = screen_height - 1;
  1112.  
  1113. // setup backbuffer clipper always
  1114. RECT screen_rect = {0,0,screen_width,screen_height};
  1115. lpddclipper = DDraw_Attach_Clipper(lpddsback,1,&screen_rect);
  1116.  
  1117. // set up windowed mode clipper
  1118. if (screen_windowed)
  1119.    {
  1120.    // set windowed clipper
  1121.    if (FAILED(lpdd->CreateClipper(0,&lpddclipperwin,NULL)))
  1122.        return(0);
  1123.  
  1124.    if (FAILED(lpddclipperwin->SetHWnd(0, main_window_handle)))
  1125.        return(0);
  1126.  
  1127.    if (FAILED(lpddsprimary->SetClipper(lpddclipperwin)))
  1128.        return(0);
  1129.    } // end if screen windowed
  1130.  
  1131. // return success
  1132. return(1);
  1133.  
  1134. } // end DDraw_Init
  1135.  
  1136. ///////////////////////////////////////////////////////////
  1137.  
  1138. int DDraw_Shutdown(void)
  1139. {
  1140. // this function release all the resources directdraw
  1141. // allocated, mainly to com objects
  1142.  
  1143. // release the clippers first
  1144. if (lpddclipper)
  1145.     lpddclipper->Release();
  1146.  
  1147. if (lpddclipperwin)
  1148.     lpddclipperwin->Release();
  1149.  
  1150. // release the palette if there is one
  1151. if (lpddpal)
  1152.    lpddpal->Release();
  1153.  
  1154. // release the secondary surface
  1155. if (lpddsback)
  1156.     lpddsback->Release();
  1157.  
  1158. // release the primary surface
  1159. if (lpddsprimary)
  1160.    lpddsprimary->Release();
  1161.  
  1162. // finally, the main dd object
  1163. if (lpdd)
  1164.     lpdd->Release();
  1165.  
  1166. // return success
  1167. return(1);
  1168. } // end DDraw_Shutdown
  1169.  
  1170. ///////////////////////////////////////////////////////////   
  1171.  
  1172. LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE4 lpdds,
  1173.                                          int num_rects,
  1174.                                          LPRECT clip_list)
  1175.  
  1176. {
  1177. // this function creates a clipper from the sent clip list and attaches
  1178. // it to the sent surface
  1179.  
  1180. int index;                         // looping var
  1181. LPDIRECTDRAWCLIPPER lpddclipper;   // pointer to the newly created dd clipper
  1182. LPRGNDATA region_data;             // pointer to the region data that contains
  1183.                                    // the header and clip list
  1184.  
  1185. // first create the direct draw clipper
  1186. if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
  1187.    return(NULL);
  1188.  
  1189. // now create the clip list from the sent data
  1190.  
  1191. // first allocate memory for region data
  1192. region_data = (LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));
  1193.  
  1194. // now copy the rects into region data
  1195. memcpy(region_data->Buffer, clip_list, sizeof(RECT)*num_rects);
  1196.  
  1197. // set up fields of header
  1198. region_data->rdh.dwSize          = sizeof(RGNDATAHEADER);
  1199. region_data->rdh.iType           = RDH_RECTANGLES;
  1200. region_data->rdh.nCount          = num_rects;
  1201. region_data->rdh.nRgnSize        = num_rects*sizeof(RECT);
  1202.  
  1203. region_data->rdh.rcBound.left    =  64000;
  1204. region_data->rdh.rcBound.top     =  64000;
  1205. region_data->rdh.rcBound.right   = -64000;
  1206. region_data->rdh.rcBound.bottom  = -64000;
  1207.  
  1208. // find bounds of all clipping regions
  1209. for (index=0; index<num_rects; index++)
  1210.     {
  1211.     // test if the next rectangle unioned with the current bound is larger
  1212.     if (clip_list[index].left < region_data->rdh.rcBound.left)
  1213.        region_data->rdh.rcBound.left = clip_list[index].left;
  1214.  
  1215.     if (clip_list[index].right > region_data->rdh.rcBound.right)
  1216.        region_data->rdh.rcBound.right = clip_list[index].right;
  1217.  
  1218.     if (clip_list[index].top < region_data->rdh.rcBound.top)
  1219.        region_data->rdh.rcBound.top = clip_list[index].top;
  1220.  
  1221.     if (clip_list[index].bottom > region_data->rdh.rcBound.bottom)
  1222.        region_data->rdh.rcBound.bottom = clip_list[index].bottom;
  1223.  
  1224.     } // end for index
  1225.  
  1226. // now we have computed the bounding rectangle region and set up the data
  1227. // now let's set the clipping list
  1228.  
  1229. if (FAILED(lpddclipper->SetClipList(region_data, 0)))
  1230.    {
  1231.    // release memory and return error
  1232.    free(region_data);
  1233.    return(NULL);
  1234.    } // end if
  1235.  
  1236. // now attach the clipper to the surface
  1237. if (FAILED(lpdds->SetClipper(lpddclipper)))
  1238.    {
  1239.    // release memory and return error
  1240.    free(region_data);
  1241.    return(NULL);
  1242.    } // end if
  1243.  
  1244. // all is well, so release memory and send back the pointer to the new clipper
  1245. free(region_data);
  1246. return(lpddclipper);
  1247.  
  1248. } // end DDraw_Attach_Clipper
  1249.  
  1250. ///////////////////////////////////////////////////////////   
  1251.    
  1252. LPDIRECTDRAWSURFACE4 DDraw_Create_Surface(int width, 
  1253.                                           int height, 
  1254.                                           int mem_flags, 
  1255.                                           USHORT color_key_value)
  1256. {
  1257. // this function creates an offscreen plain surface
  1258.  
  1259. DDSURFACEDESC2 ddsd;         // working description
  1260. LPDIRECTDRAWSURFACE4 lpdds;  // temporary surface
  1261.     
  1262. // set to access caps, width, and height
  1263. memset(&ddsd,0,sizeof(ddsd));
  1264. ddsd.dwSize  = sizeof(ddsd);
  1265. ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
  1266.  
  1267. // set dimensions of the new bitmap surface
  1268. ddsd.dwWidth  =  width;
  1269. ddsd.dwHeight =  height;
  1270.  
  1271. // set surface to offscreen plain
  1272. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
  1273.  
  1274. // create the surface
  1275. if (FAILED(lpdd->CreateSurface(&ddsd,&lpdds,NULL)))
  1276.    return(NULL);
  1277.  
  1278. // set color key to default color 000
  1279. // note that if this is a 8bit bob then palette index 0 will be 
  1280. // transparent by default
  1281. // note that if this is a 16bit bob then RGB value 000 will be 
  1282. // transparent
  1283. DDCOLORKEY color_key; // used to set color key
  1284. color_key.dwColorSpaceLowValue  = color_key_value;
  1285. color_key.dwColorSpaceHighValue = color_key_value;
  1286.  
  1287. // now set the color key for source blitting
  1288. lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);
  1289.  
  1290. // return surface
  1291. return(lpdds);
  1292. } // end DDraw_Create_Surface
  1293.  
  1294. ///////////////////////////////////////////////////////////   
  1295.    
  1296. int DDraw_Flip(void)
  1297. {
  1298. // this function flip the primary surface with the secondary surface
  1299.  
  1300. // test if either of the buffers are locked
  1301. if (primary_buffer || back_buffer)
  1302.    return(0);
  1303.  
  1304. // flip pages
  1305. if (!screen_windowed)
  1306.    while(FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));
  1307. else
  1308.    {
  1309.    RECT    dest_rect;    // used to compute destination rectangle
  1310.  
  1311.    // get the window's rectangle in screen coordinates
  1312.    GetWindowRect(main_window_handle, &dest_rect);   
  1313.  
  1314.    // compute the destination rectangle
  1315.    dest_rect.left   +=window_client_x0;
  1316.    dest_rect.top    +=window_client_y0;
  1317.  
  1318.    dest_rect.right  =dest_rect.left+640;
  1319.    dest_rect.bottom =dest_rect.top +480;
  1320.  
  1321.    // clip the screen coords 
  1322.      
  1323.    
  1324.     
  1325.    // blit the entire back surface to the primary
  1326.    if (FAILED(lpddsprimary->Blt(&dest_rect, lpddsback,NULL,DDBLT_WAIT,NULL)))
  1327.        return(0);    
  1328.  
  1329.    } // end if
  1330.  
  1331. // return success
  1332. return(1);
  1333.  
  1334. } // end DDraw_Flip
  1335.  
  1336. ///////////////////////////////////////////////////////////   
  1337.    
  1338. int DDraw_Wait_For_Vsync(void)
  1339. {
  1340. // this function waits for a vertical blank to begin
  1341.     
  1342. lpdd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN,0);
  1343.  
  1344. // return success
  1345. return(1);
  1346. } // end DDraw_Wait_For_Vsync
  1347.  
  1348. ///////////////////////////////////////////////////////////   
  1349.    
  1350. int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE4 lpdds, USHORT color, RECT *client)
  1351. {
  1352. DDBLTFX ddbltfx; // this contains the DDBLTFX structure
  1353.  
  1354. // clear out the structure and set the size field 
  1355. DDRAW_INIT_STRUCT(ddbltfx);
  1356.  
  1357. // set the dwfillcolor field to the desired color
  1358. ddbltfx.dwFillColor = color; 
  1359.  
  1360. // ready to blt to surface
  1361. lpdds->Blt(client,     // ptr to dest rectangle
  1362.            NULL,       // ptr to source surface, NA            
  1363.            NULL,       // ptr to source rectangle, NA
  1364.            DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                   
  1365.            &ddbltfx);  // ptr to DDBLTFX structure
  1366.  
  1367. // return success
  1368. return(1);
  1369. } // end DDraw_Fill_Surface
  1370.  
  1371. ///////////////////////////////////////////////////////////   
  1372.    
  1373. UCHAR *DDraw_Lock_Surface(LPDIRECTDRAWSURFACE4 lpdds, int *lpitch)
  1374. {
  1375. // this function locks the sent surface and returns a pointer to it
  1376.  
  1377. // is this surface valid
  1378. if (!lpdds)
  1379.    return(NULL);
  1380.  
  1381. // lock the surface
  1382. DDRAW_INIT_STRUCT(ddsd);
  1383. lpdds->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1384.  
  1385. // set the memory pitch
  1386. if (lpitch)
  1387.    *lpitch = ddsd.lPitch;
  1388.  
  1389. // return pointer to surface
  1390. return((UCHAR *)ddsd.lpSurface);
  1391.  
  1392. } // end DDraw_Lock_Surface
  1393.  
  1394. ///////////////////////////////////////////////////////////   
  1395.    
  1396. int DDraw_Unlock_Surface(LPDIRECTDRAWSURFACE4 lpdds)
  1397. {
  1398. // this unlocks a general surface
  1399.  
  1400. // is this surface valid
  1401. if (!lpdds)
  1402.    return(0);
  1403.  
  1404. // unlock the surface memory
  1405. lpdds->Unlock(NULL);
  1406.  
  1407. // return success
  1408. return(1);
  1409. } // end DDraw_Unlock_Surface
  1410.  
  1411. ///////////////////////////////////////////////////////////
  1412.  
  1413. UCHAR *DDraw_Lock_Primary_Surface(void)
  1414. {
  1415. // this function locks the priamary surface and returns a pointer to it
  1416. // and updates the global variables primary_buffer, and primary_lpitch
  1417.  
  1418. // is this surface already locked
  1419. if (primary_buffer)
  1420.    {
  1421.    // return to current lock
  1422.    return(primary_buffer);
  1423.    } // end if
  1424.  
  1425. // lock the primary surface
  1426. DDRAW_INIT_STRUCT(ddsd);
  1427. lpddsprimary->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1428.  
  1429. // set globals
  1430. primary_buffer = (UCHAR *)ddsd.lpSurface;
  1431. primary_lpitch = ddsd.lPitch;
  1432.  
  1433. // return pointer to surface
  1434. return(primary_buffer);
  1435.  
  1436. } // end DDraw_Lock_Primary_Surface
  1437.  
  1438. ///////////////////////////////////////////////////////////   
  1439.    
  1440. int DDraw_Unlock_Primary_Surface(void)
  1441. {
  1442. // this unlocks the primary
  1443.  
  1444. // is this surface valid
  1445. if (!primary_buffer)
  1446.    return(0);
  1447.  
  1448. // unlock the primary surface
  1449. lpddsprimary->Unlock(NULL);
  1450.  
  1451. // reset the primary surface
  1452. primary_buffer = NULL;
  1453. primary_lpitch = 0;
  1454.  
  1455. // return success
  1456. return(1);
  1457. } // end DDraw_Unlock_Primary_Surface
  1458.  
  1459. //////////////////////////////////////////////////////////
  1460.  
  1461. UCHAR *DDraw_Lock_Back_Surface(void)
  1462. {
  1463. // this function locks the secondary back surface and returns a pointer to it
  1464. // and updates the global variables secondary buffer, and back_lpitch
  1465.  
  1466. // is this surface already locked
  1467. if (back_buffer)
  1468.    {
  1469.    // return to current lock
  1470.    return(back_buffer);
  1471.    } // end if
  1472.  
  1473. // lock the primary surface
  1474. DDRAW_INIT_STRUCT(ddsd);
  1475. lpddsback->Lock(NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,NULL); 
  1476.  
  1477. // set globals
  1478. back_buffer = (UCHAR *)ddsd.lpSurface;
  1479. back_lpitch = ddsd.lPitch;
  1480.  
  1481. // return pointer to surface
  1482. return(back_buffer);
  1483.  
  1484. } // end DDraw_Lock_Back_Surface
  1485.  
  1486. ///////////////////////////////////////////////////////////   
  1487.    
  1488. int DDraw_Unlock_Back_Surface(void)
  1489. {
  1490. // this unlocks the secondary
  1491.  
  1492. // is this surface valid
  1493. if (!back_buffer)
  1494.    return(0);
  1495.  
  1496. // unlock the secondary surface
  1497. lpddsback->Unlock(NULL);
  1498.  
  1499. // reset the secondary surface
  1500. back_buffer = NULL;
  1501. back_lpitch = 0;
  1502.  
  1503. // return success
  1504. return(1);
  1505. } // end DDraw_Unlock_Back_Surface
  1506.  
  1507. ///////////////////////////////////////////////////////////
  1508.  
  1509. DWORD Get_Clock(void)
  1510. {
  1511. // this function returns the current tick count
  1512.  
  1513. // return time
  1514. return(GetTickCount());
  1515.  
  1516. } // end Get_Clock
  1517.  
  1518. ///////////////////////////////////////////////////////////
  1519.  
  1520. DWORD Start_Clock(void)
  1521. {
  1522. // this function starts the clock, that is, saves the current
  1523. // count, use in conjunction with Wait_Clock()
  1524.  
  1525. return(start_clock_count = Get_Clock());
  1526.  
  1527. } // end Start_Clock
  1528.  
  1529. ////////////////////////////////////////////////////////////
  1530.  
  1531. DWORD Wait_Clock(DWORD count)
  1532. {
  1533. // this function is used to wait for a specific number of clicks
  1534. // since the call to Start_Clock
  1535.  
  1536. while((Get_Clock() - start_clock_count) < count);
  1537. return(Get_Clock());
  1538.  
  1539. } // end Wait_Clock
  1540.  
  1541. ///////////////////////////////////////////////////////////
  1542.  
  1543. int Draw_Clip_Line16(int x0,int y0, int x1, int y1, int color, 
  1544.                     UCHAR *dest_buffer, int lpitch)
  1545. {
  1546. // this function draws a clipped line
  1547.  
  1548. int cxs, cys,
  1549.     cxe, cye;
  1550.  
  1551. // clip and draw each line
  1552. cxs = x0;
  1553. cys = y0;
  1554. cxe = x1;
  1555. cye = y1;
  1556.  
  1557. // clip the line
  1558. if (Clip_Line(cxs,cys,cxe,cye))
  1559.     Draw_Line16(cxs, cys, cxe,cye,color,dest_buffer,lpitch);
  1560.  
  1561. // return success
  1562. return(1);
  1563.  
  1564. } // end Draw_Clip_Line16
  1565.  
  1566.  
  1567. ///////////////////////////////////////////////////////////
  1568.  
  1569. int Draw_Clip_Line(int x0,int y0, int x1, int y1, int color, 
  1570.                     UCHAR *dest_buffer, int lpitch)
  1571. {
  1572. // this function draws a wireframe triangle
  1573.  
  1574. int cxs, cys,
  1575.     cxe, cye;
  1576.  
  1577. // clip and draw each line
  1578. cxs = x0;
  1579. cys = y0;
  1580. cxe = x1;
  1581. cye = y1;
  1582.  
  1583. // clip the line
  1584. if (Clip_Line(cxs,cys,cxe,cye))
  1585.     Draw_Line(cxs, cys, cxe,cye,color,dest_buffer,lpitch);
  1586.  
  1587. // return success
  1588. return(1);
  1589.  
  1590. } // end Draw_Clip_Line
  1591.  
  1592. ///////////////////////////////////////////////////////////
  1593.  
  1594. int Clip_Line(int &x1,int &y1,int &x2, int &y2)
  1595. {
  1596. // this function clips the sent line using the globally defined clipping
  1597. // region
  1598.  
  1599. // internal clipping codes
  1600. #define CLIP_CODE_C  0x0000
  1601. #define CLIP_CODE_N  0x0008
  1602. #define CLIP_CODE_S  0x0004
  1603. #define CLIP_CODE_E  0x0002
  1604. #define CLIP_CODE_W  0x0001
  1605.  
  1606. #define CLIP_CODE_NE 0x000a
  1607. #define CLIP_CODE_SE 0x0006
  1608. #define CLIP_CODE_NW 0x0009 
  1609. #define CLIP_CODE_SW 0x0005
  1610.  
  1611. int xc1=x1, 
  1612.     yc1=y1, 
  1613.     xc2=x2, 
  1614.     yc2=y2;
  1615.  
  1616. int p1_code=0, 
  1617.     p2_code=0;
  1618.  
  1619. // determine codes for p1 and p2
  1620. if (y1 < min_clip_y)
  1621.     p1_code|=CLIP_CODE_N;
  1622. else
  1623. if (y1 > max_clip_y)
  1624.     p1_code|=CLIP_CODE_S;
  1625.  
  1626. if (x1 < min_clip_x)
  1627.     p1_code|=CLIP_CODE_W;
  1628. else
  1629. if (x1 > max_clip_x)
  1630.     p1_code|=CLIP_CODE_E;
  1631.  
  1632. if (y2 < min_clip_y)
  1633.     p2_code|=CLIP_CODE_N;
  1634. else
  1635. if (y2 > max_clip_y)
  1636.     p2_code|=CLIP_CODE_S;
  1637.  
  1638. if (x2 < min_clip_x)
  1639.     p2_code|=CLIP_CODE_W;
  1640. else
  1641. if (x2 > max_clip_x)
  1642.     p2_code|=CLIP_CODE_E;
  1643.  
  1644. // try and trivially reject
  1645. if ((p1_code & p2_code)) 
  1646.     return(0);
  1647.  
  1648. // test for totally visible, if so leave points untouched
  1649. if (p1_code==0 && p2_code==0)
  1650.     return(1);
  1651.  
  1652. // determine end clip point for p1
  1653. switch(p1_code)
  1654.       {
  1655.       case CLIP_CODE_C: break;
  1656.  
  1657.       case CLIP_CODE_N:
  1658.            {
  1659.            yc1 = min_clip_y;
  1660.            xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1661.            } break;
  1662.       case CLIP_CODE_S:
  1663.            {
  1664.            yc1 = max_clip_y;
  1665.            xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
  1666.            } break;
  1667.  
  1668.       case CLIP_CODE_W:
  1669.            {
  1670.            xc1 = min_clip_x;
  1671.            yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
  1672.            } break;
  1673.         
  1674.       case CLIP_CODE_E:
  1675.            {
  1676.            xc1 = max_clip_x;
  1677.            yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1678.            } break;
  1679.  
  1680.     // these cases are more complex, must compute 2 intersections
  1681.       case CLIP_CODE_NE:
  1682.            {
  1683.            // north hline intersection
  1684.            yc1 = min_clip_y;
  1685.            xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1686.  
  1687.            // test if intersection is valid, of so then done, else compute next
  1688.             if (xc1 < min_clip_x || xc1 > max_clip_x)
  1689.                 {
  1690.                 // east vline intersection
  1691.                 xc1 = max_clip_x;
  1692.                 yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1693.                 } // end if
  1694.  
  1695.            } break;
  1696.       
  1697.       case CLIP_CODE_SE:
  1698.              {
  1699.            // south hline intersection
  1700.            yc1 = max_clip_y;
  1701.            xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);    
  1702.  
  1703.            // test if intersection is valid, of so then done, else compute next
  1704.            if (xc1 < min_clip_x || xc1 > max_clip_x)
  1705.               {
  1706.               // east vline intersection
  1707.               xc1 = max_clip_x;
  1708.               yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
  1709.               } // end if
  1710.  
  1711.            } break;
  1712.         
  1713.       case CLIP_CODE_NW: 
  1714.              {
  1715.            // north hline intersection
  1716.            yc1 = min_clip_y;
  1717.            xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
  1718.            
  1719.            // test if intersection is valid, of so then done, else compute next
  1720.            if (xc1 < min_clip_x || xc1 > max_clip_x)
  1721.               {
  1722.               xc1 = min_clip_x;
  1723.               yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);    
  1724.               } // end if
  1725.  
  1726.            } break;
  1727.             
  1728.       case CLIP_CODE_SW:
  1729.            {
  1730.            // south hline intersection
  1731.            yc1 = max_clip_y;
  1732.            xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);    
  1733.            
  1734.            // test if intersection is valid, of so then done, else compute next
  1735.            if (xc1 < min_clip_x || xc1 > max_clip_x)
  1736.               {
  1737.               xc1 = min_clip_x;
  1738.               yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);    
  1739.               } // end if
  1740.  
  1741.            } break;
  1742.  
  1743.       default:break;
  1744.  
  1745.       } // end switch
  1746.  
  1747. // determine clip point for p2
  1748. switch(p2_code)
  1749.       {
  1750.       case CLIP_CODE_C: break;
  1751.  
  1752.       case CLIP_CODE_N:
  1753.            {
  1754.            yc2 = min_clip_y;
  1755.            xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
  1756.            } break;
  1757.  
  1758.       case CLIP_CODE_S:
  1759.            {
  1760.            yc2 = max_clip_y;
  1761.            xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
  1762.            } break;
  1763.  
  1764.       case CLIP_CODE_W:
  1765.            {
  1766.            xc2 = min_clip_x;
  1767.            yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
  1768.            } break;
  1769.         
  1770.       case CLIP_CODE_E:
  1771.            {
  1772.            xc2 = max_clip_x;
  1773.            yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
  1774.            } break;
  1775.  
  1776.         // these cases are more complex, must compute 2 intersections
  1777.       case CLIP_CODE_NE:
  1778.            {
  1779.            // north hline intersection
  1780.            yc2 = min_clip_y;
  1781.            xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
  1782.  
  1783.            // test if intersection is valid, of so then done, else compute next
  1784.             if (xc2 < min_clip_x || xc2 > max_clip_x)
  1785.                 {
  1786.                 // east vline intersection
  1787.                 xc2 = max_clip_x;
  1788.                 yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
  1789.                 } // end if
  1790.  
  1791.            } break;
  1792.       
  1793.       case CLIP_CODE_SE:
  1794.              {
  1795.            // south hline intersection
  1796.            yc2 = max_clip_y;
  1797.            xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);    
  1798.  
  1799.            // test if intersection is valid, of so then done, else compute next
  1800.            if (xc2 < min_clip_x || xc2 > max_clip_x)
  1801.               {
  1802.               // east vline intersection
  1803.               xc2 = max_clip_x;
  1804.               yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
  1805.               } // end if
  1806.  
  1807.            } break;
  1808.         
  1809.       case CLIP_CODE_NW: 
  1810.              {
  1811.            // north hline intersection
  1812.            yc2 = min_clip_y;
  1813.            xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
  1814.            
  1815.            // test if intersection is valid, of so then done, else compute next
  1816.            if (xc2 < min_clip_x || xc2 > max_clip_x)
  1817.               {
  1818.               xc2 = min_clip_x;
  1819.               yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);    
  1820.               } // end if
  1821.  
  1822.            } break;
  1823.             
  1824.       case CLIP_CODE_SW:
  1825.            {
  1826.            // south hline intersection
  1827.            yc2 = max_clip_y;
  1828.            xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);    
  1829.            
  1830.            // test if intersection is valid, of so then done, else compute next
  1831.            if (xc2 < min_clip_x || xc2 > max_clip_x)
  1832.               {
  1833.               xc2 = min_clip_x;
  1834.               yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);    
  1835.               } // end if
  1836.  
  1837.            } break;
  1838.     
  1839.       default:break;
  1840.  
  1841.       } // end switch
  1842.  
  1843. // do bounds check
  1844. if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
  1845.     (yc1 < min_clip_y) || (yc1 > max_clip_y) ||
  1846.     (xc2 < min_clip_x) || (xc2 > max_clip_x) ||
  1847.     (yc2 < min_clip_y) || (yc2 > max_clip_y) )
  1848.     {
  1849.     return(0);
  1850.     } // end if
  1851.  
  1852. // store vars back
  1853. x1 = xc1;
  1854. y1 = yc1;
  1855. x2 = xc2;
  1856. y2 = yc2;
  1857.  
  1858. return(1);
  1859.  
  1860. } // end Clip_Line
  1861.  
  1862. ///////////////////////////////////////////////////////////
  1863.  
  1864. int Draw_Line(int x0, int y0, // starting position 
  1865.               int x1, int y1, // ending position
  1866.               int color,     // color index
  1867.               UCHAR *vb_start, int lpitch) // video buffer and memory pitch
  1868. {
  1869. // this function draws a line from xo,yo to x1,y1 using differential error
  1870. // terms (based on Bresenahams work)
  1871.  
  1872. int dx,             // difference in x's
  1873.     dy,             // difference in y's
  1874.     dx2,            // dx,dy * 2
  1875.     dy2, 
  1876.     x_inc,          // amount in pixel space to move during drawing
  1877.     y_inc,          // amount in pixel space to move during drawing
  1878.     error,          // the discriminant i.e. error i.e. decision variable
  1879.     index;          // used for looping
  1880.  
  1881. // pre-compute first pixel address in video buffer
  1882. vb_start = vb_start + x0 + y0*lpitch;
  1883.  
  1884. // compute horizontal and vertical deltas
  1885. dx = x1-x0;
  1886. dy = y1-y0;
  1887.  
  1888. // test which direction the line is going in i.e. slope angle
  1889. if (dx>=0)
  1890.    {
  1891.    x_inc = 1;
  1892.  
  1893.    } // end if line is moving right
  1894. else
  1895.    {
  1896.    x_inc = -1;
  1897.    dx    = -dx;  // need absolute value
  1898.  
  1899.    } // end else moving left
  1900.  
  1901. // test y component of slope
  1902.  
  1903. if (dy>=0)
  1904.    {
  1905.    y_inc = lpitch;
  1906.    } // end if line is moving down
  1907. else
  1908.    {
  1909.    y_inc = -lpitch;
  1910.    dy    = -dy;  // need absolute value
  1911.  
  1912.    } // end else moving up
  1913.  
  1914. // compute (dx,dy) * 2
  1915. dx2 = dx << 1;
  1916. dy2 = dy << 1;
  1917.  
  1918. // now based on which delta is greater we can draw the line
  1919. if (dx > dy)
  1920.    {
  1921.    // initialize error term
  1922.    error = dy2 - dx; 
  1923.  
  1924.    // draw the line
  1925.    for (index=0; index <= dx; index++)
  1926.        {
  1927.        // set the pixel
  1928.        *vb_start = color;
  1929.  
  1930.        // test if error has overflowed
  1931.        if (error >= 0) 
  1932.           {
  1933.           error-=dx2;
  1934.  
  1935.           // move to next line
  1936.           vb_start+=y_inc;
  1937.  
  1938.        } // end if error overflowed
  1939.  
  1940.        // adjust the error term
  1941.        error+=dy2;
  1942.  
  1943.        // move to the next pixel
  1944.        vb_start+=x_inc;
  1945.  
  1946.        } // end for
  1947.  
  1948.    } // end if |slope| <= 1
  1949. else
  1950.    {
  1951.    // initialize error term
  1952.    error = dx2 - dy; 
  1953.  
  1954.    // draw the line
  1955.    for (index=0; index <= dy; index++)
  1956.        {
  1957.        // set the pixel
  1958.        *vb_start = color;
  1959.  
  1960.        // test if error overflowed
  1961.        if (error >= 0)
  1962.           {
  1963.           error-=dy2;
  1964.  
  1965.           // move to next line
  1966.           vb_start+=x_inc;
  1967.  
  1968.           } // end if error overflowed
  1969.  
  1970.        // adjust the error term
  1971.        error+=dx2;
  1972.  
  1973.        // move to the next pixel
  1974.        vb_start+=y_inc;
  1975.  
  1976.        } // end for
  1977.  
  1978.    } // end else |slope| > 1
  1979.  
  1980. // return success
  1981. return(1);
  1982.  
  1983. } // end Draw_Line
  1984.  
  1985. ///////////////////////////////////////////////////////////
  1986.  
  1987. int Draw_Line16(int x0, int y0, // starting position 
  1988.                 int x1, int y1, // ending position
  1989.                 int color,     // color index
  1990.                 UCHAR *vb_start, int lpitch) // video buffer and memory pitch
  1991. {
  1992. // this function draws a line from xo,yo to x1,y1 using differential error
  1993. // terms (based on Bresenahams work)
  1994.  
  1995. int dx,             // difference in x's
  1996.     dy,             // difference in y's
  1997.     dx2,            // dx,dy * 2
  1998.     dy2, 
  1999.     x_inc,          // amount in pixel space to move during drawing
  2000.     y_inc,          // amount in pixel space to move during drawing
  2001.     error,          // the discriminant i.e. error i.e. decision variable
  2002.     index;          // used for looping
  2003.  
  2004. int lpitch_2 = lpitch >> 1; // USHORT strided lpitch
  2005.  
  2006. // pre-compute first pixel address in video buffer based on 16bit data
  2007. USHORT *vb_start2 = (USHORT *)vb_start + x0 + y0*lpitch_2;
  2008.  
  2009. // compute horizontal and vertical deltas
  2010. dx = x1-x0;
  2011. dy = y1-y0;
  2012.  
  2013. // test which direction the line is going in i.e. slope angle
  2014. if (dx>=0)
  2015.    {
  2016.    x_inc = 1;
  2017.  
  2018.    } // end if line is moving right
  2019. else
  2020.    {
  2021.    x_inc = -1;
  2022.    dx    = -dx;  // need absolute value
  2023.  
  2024.    } // end else moving left
  2025.  
  2026. // test y component of slope
  2027.  
  2028. if (dy>=0)
  2029.    {
  2030.    y_inc = lpitch_2;
  2031.    } // end if line is moving down
  2032. else
  2033.    {
  2034.    y_inc = -lpitch_2;
  2035.    dy    = -dy;  // need absolute value
  2036.  
  2037.    } // end else moving up
  2038.  
  2039. // compute (dx,dy) * 2
  2040. dx2 = dx << 1;
  2041. dy2 = dy << 1;
  2042.  
  2043. // now based on which delta is greater we can draw the line
  2044. if (dx > dy)
  2045.    {
  2046.    // initialize error term
  2047.    error = dy2 - dx; 
  2048.  
  2049.    // draw the line
  2050.    for (index=0; index <= dx; index++)
  2051.        {
  2052.        // set the pixel
  2053.        *vb_start2 = (USHORT)color;
  2054.  
  2055.        // test if error has overflowed
  2056.        if (error >= 0) 
  2057.           {
  2058.           error-=dx2;
  2059.  
  2060.           // move to next line
  2061.           vb_start2+=y_inc;
  2062.  
  2063.        } // end if error overflowed
  2064.  
  2065.        // adjust the error term
  2066.        error+=dy2;
  2067.  
  2068.        // move to the next pixel
  2069.        vb_start2+=x_inc;
  2070.  
  2071.        } // end for
  2072.  
  2073.    } // end if |slope| <= 1
  2074. else
  2075.    {
  2076.    // initialize error term
  2077.    error = dx2 - dy; 
  2078.  
  2079.    // draw the line
  2080.    for (index=0; index <= dy; index++)
  2081.        {
  2082.        // set the pixel
  2083.        *vb_start2 = (USHORT)color;
  2084.  
  2085.        // test if error overflowed
  2086.        if (error >= 0)
  2087.           {
  2088.           error-=dy2;
  2089.  
  2090.           // move to next line
  2091.           vb_start2+=x_inc;
  2092.  
  2093.           } // end if error overflowed
  2094.  
  2095.        // adjust the error term
  2096.        error+=dx2;
  2097.  
  2098.        // move to the next pixel
  2099.        vb_start2+=y_inc;
  2100.  
  2101.        } // end for
  2102.  
  2103.    } // end else |slope| > 1
  2104.  
  2105. // return success
  2106. return(1);
  2107.  
  2108. } // end Draw_Line16
  2109.  
  2110. ///////////////////////////////////////////////////////////
  2111.  
  2112. inline int Draw_Pixel(int x, int y,int color,
  2113.                UCHAR *video_buffer, int lpitch)
  2114. {
  2115. // this function plots a single pixel at x,y with color
  2116.  
  2117. video_buffer[x + y*lpitch] = color;
  2118.  
  2119. // return success
  2120. return(1);
  2121.  
  2122. } // end Draw_Pixel
  2123.  
  2124. ///////////////////////////////////////////////////////////   
  2125.    
  2126. inline int Draw_Pixel16(int x, int y,int color,
  2127.                         USHORT *video_buffer, int lpitch)
  2128. {
  2129. // this function plots a single pixel at x,y with color
  2130.  
  2131. video_buffer[x + y*(lpitch >> 1)] = color;
  2132.  
  2133. // return success
  2134. return(1);
  2135.  
  2136. } // end Draw_Pixel16
  2137.  
  2138. ///////////////////////////////////////////////////////////   
  2139.  
  2140.  
  2141. int Draw_Rectangle(int x1, int y1, int x2, int y2, int color,
  2142.                    LPDIRECTDRAWSURFACE4 lpdds)
  2143. {
  2144. // this function uses directdraw to draw a filled rectangle
  2145.  
  2146. DDBLTFX ddbltfx; // this contains the DDBLTFX structure
  2147. RECT fill_area;  // this contains the destination rectangle
  2148.  
  2149. // clear out the structure and set the size field 
  2150. DDRAW_INIT_STRUCT(ddbltfx);
  2151.  
  2152. // set the dwfillcolor field to the desired color
  2153. ddbltfx.dwFillColor = color; 
  2154.  
  2155. // fill in the destination rectangle data (your data)
  2156. fill_area.top    = y1;
  2157. fill_area.left   = x1;
  2158. fill_area.bottom = y2;
  2159. fill_area.right  = x2;
  2160.  
  2161. // ready to blt to surface, in this case blt to primary
  2162. lpdds->Blt(&fill_area, // ptr to dest rectangle
  2163.            NULL,       // ptr to source surface, NA            
  2164.            NULL,       // ptr to source rectangle, NA
  2165.            DDBLT_COLORFILL | DDBLT_WAIT,   // fill and wait                   
  2166.            &ddbltfx);  // ptr to DDBLTFX structure
  2167.  
  2168. // return success
  2169. return(1);
  2170.  
  2171. } // end Draw_Rectangle
  2172.  
  2173. ///////////////////////////////////////////////////////////
  2174.    
  2175. int Set_Palette_Entry(int color_index, LPPALETTEENTRY color)
  2176. {
  2177. // this function sets a palette color in the palette
  2178. lpddpal->SetEntries(0,color_index,1,color);
  2179.  
  2180. // set data in shadow palette
  2181. memcpy(&palette[color_index],color,sizeof(PALETTEENTRY));
  2182.  
  2183. // return success
  2184. return(1);
  2185. } // end Set_Palette_Entry
  2186.  
  2187. ///////////////////////////////////////////////////////////   
  2188.    
  2189. int Get_Palette_Entry(int color_index,LPPALETTEENTRY color)
  2190. {
  2191. // this function retrieves a palette entry from the color
  2192. // palette
  2193.  
  2194. // copy data out from shadow palette
  2195. memcpy(color, &palette[color_index],sizeof(PALETTEENTRY));
  2196.  
  2197. // return success
  2198. return(1);
  2199. } // end Get_Palette_Entry
  2200.  
  2201. ///////////////////////////////////////////////////////////
  2202.    
  2203. int Load_Palette_From_File(char *filename, LPPALETTEENTRY palette)
  2204. {
  2205. // this function loads a palette from disk into a palette
  2206. // structure, but does not set the pallette
  2207.  
  2208. FILE *fp_file; // working file
  2209.  
  2210. // try and open file
  2211. if ((fp_file = fopen(filename,"r"))==NULL)
  2212.    return(0);
  2213.  
  2214. // read in all 256 colors RGBF
  2215. for (int index=0; index<MAX_COLORS_PALETTE; index++)
  2216.     {
  2217.     // read the next entry in
  2218.     fscanf(fp_file,"%d %d %d %d",&palette[index].peRed,
  2219.                                  &palette[index].peGreen,
  2220.                                  &palette[index].peBlue,                                
  2221.                                  &palette[index].peFlags);
  2222.     } // end for index
  2223.  
  2224. // close the file
  2225. fclose(fp_file);
  2226.  
  2227. // return success
  2228. return(1);
  2229. } // end Load_Palette_From_Disk
  2230.  
  2231. ///////////////////////////////////////////////////////////   
  2232.    
  2233. int Save_Palette_To_File(char *filename, LPPALETTEENTRY palette)
  2234. {
  2235. // this function saves a palette to disk
  2236.  
  2237. FILE *fp_file; // working file
  2238.  
  2239. // try and open file
  2240. if ((fp_file = fopen(filename,"w"))==NULL)
  2241.    return(0);
  2242.  
  2243. // write in all 256 colors RGBF
  2244. for (int index=0; index<MAX_COLORS_PALETTE; index++)
  2245.     {
  2246.     // read the next entry in
  2247.     fprintf(fp_file,"\n%d %d %d %d",palette[index].peRed,
  2248.                                     palette[index].peGreen,
  2249.                                     palette[index].peBlue,                                
  2250.                                     palette[index].peFlags);
  2251.     } // end for index
  2252.  
  2253. // close the file
  2254. fclose(fp_file);
  2255.  
  2256. // return success
  2257. return(1);
  2258.  
  2259. } // end Save_Palette_To_Disk
  2260.  
  2261. ///////////////////////////////////////////////////////////
  2262.  
  2263. int Save_Palette(LPPALETTEENTRY sav_palette)
  2264. {
  2265. // this function saves the current palette 
  2266.  
  2267. memcpy(sav_palette, palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  2268.  
  2269. // return success
  2270. return(1);
  2271. } // end Save_Palette
  2272.  
  2273. ///////////////////////////////////////////////////////////   
  2274.    
  2275. int Set_Palette(LPPALETTEENTRY set_palette)
  2276. {
  2277. // this function writes the sent palette
  2278.  
  2279. // first save the new palette in shadow
  2280. memcpy(palette, set_palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  2281.  
  2282. // now set the new palette
  2283. lpddpal->SetEntries(0,0,MAX_COLORS_PALETTE,palette);
  2284.  
  2285. // return success
  2286. return(1);
  2287. } // end Set_Palette
  2288.  
  2289. ///////////////////////////////////////////////////////////
  2290.  
  2291. int Rotate_Colors(int start_index, int end_index)
  2292. {
  2293. // this function rotates the color between start and end
  2294.  
  2295. int colors = end_index - start_index + 1;
  2296.  
  2297. PALETTEENTRY work_pal[MAX_COLORS_PALETTE]; // working palette
  2298.  
  2299. // get the color palette
  2300. lpddpal->GetEntries(0,start_index,colors,work_pal);
  2301.  
  2302. // shift the colors
  2303. lpddpal->SetEntries(0,start_index+1,colors-1,work_pal);
  2304.  
  2305. // fix up the last color
  2306. lpddpal->SetEntries(0,start_index,1,&work_pal[colors - 1]);
  2307.  
  2308. // update shadow palette
  2309. lpddpal->GetEntries(0,0,MAX_COLORS_PALETTE,palette);
  2310.  
  2311. // return success
  2312. return(1);
  2313.  
  2314. } // end Rotate_Colors
  2315.  
  2316. ///////////////////////////////////////////////////////////   
  2317.    
  2318. int Blink_Colors(int command, BLINKER_PTR new_light, int id)
  2319. {
  2320. // this function blinks a set of lights
  2321.  
  2322. static BLINKER lights[256]; // supports up to 256 blinking lights
  2323. static int initialized = 0; // tracks if function has initialized
  2324.  
  2325. // test if this is the first time function has ran
  2326. if (!initialized)
  2327.    {
  2328.    // set initialized
  2329.    initialized = 1;
  2330.  
  2331.    // clear out all structures
  2332.    memset((void *)lights,0, sizeof(lights));
  2333.  
  2334.    } // end if
  2335.  
  2336. // now test what command user is sending
  2337. switch (command)
  2338.        {
  2339.        case BLINKER_ADD: // add a light to the database
  2340.             {
  2341.             // run thru database and find an open light
  2342.             for (int index=0; index < 256; index++)
  2343.                 {
  2344.                 // is this light available?
  2345.                 if (lights[index].state == 0)
  2346.                    {
  2347.                    // set light up
  2348.                    lights[index] = *new_light;
  2349.  
  2350.                    // set internal fields up
  2351.                    lights[index].counter =  0;
  2352.                    lights[index].state   = -1; // off
  2353.  
  2354.                    // update palette entry
  2355.                    lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].off_color);
  2356.  
  2357.                    // return id to caller
  2358.                    return(index);
  2359.  
  2360.                    } // end if
  2361.  
  2362.                 } // end for index
  2363.  
  2364.             } break;
  2365.  
  2366.        case BLINKER_DELETE: // delete the light indicated by id
  2367.             {
  2368.             // delete the light sent in id 
  2369.             if (lights[id].state != 0)
  2370.                {
  2371.                // kill the light
  2372.                memset((void *)&lights[id],0,sizeof(BLINKER));
  2373.  
  2374.                // return id
  2375.                return(id);
  2376.  
  2377.                } // end if
  2378.             else
  2379.                 return(-1); // problem
  2380.  
  2381.  
  2382.             } break;
  2383.  
  2384.        case BLINKER_UPDATE: // update the light indicated by id
  2385.             { 
  2386.             // make sure light is active
  2387.             if (lights[id].state != 0)
  2388.                {
  2389.                // update on/off parms only
  2390.                lights[id].on_color  = new_light->on_color; 
  2391.                lights[id].off_color = new_light->off_color;
  2392.                lights[id].on_time   = new_light->on_time;
  2393.                lights[id].off_time  = new_light->off_time; 
  2394.  
  2395.                // update palette entry
  2396.                if (lights[id].state == -1)
  2397.                   lpddpal->SetEntries(0,lights[id].color_index,1,&lights[id].off_color);
  2398.                else
  2399.                   lpddpal->SetEntries(0,lights[id].color_index,1,&lights[id].on_color);
  2400.  
  2401.                // return id
  2402.                return(id);
  2403.  
  2404.                } // end if
  2405.             else
  2406.                 return(-1); // problem
  2407.  
  2408.             } break;
  2409.  
  2410.        case BLINKER_RUN: // run the algorithm
  2411.             {
  2412.             // run thru database and process each light
  2413.             for (int index=0; index < 256; index++)
  2414.                 {
  2415.                 // is this active?
  2416.                 if (lights[index].state == -1)
  2417.                    {
  2418.                    // update counter
  2419.                    if (++lights[index].counter >= lights[index].off_time)
  2420.                       {
  2421.                       // reset counter
  2422.                       lights[index].counter = 0;
  2423.  
  2424.                       // change states 
  2425.                       lights[index].state = -lights[index].state;               
  2426.  
  2427.                       // update color
  2428.                       lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].on_color);
  2429.  
  2430.                       } // end if
  2431.                  
  2432.                    } // end if
  2433.                 else
  2434.                 if (lights[index].state == 1)
  2435.                    {
  2436.                    // update counter
  2437.                    if (++lights[index].counter >= lights[index].on_time)
  2438.                       {
  2439.                       // reset counter
  2440.                       lights[index].counter = 0;
  2441.  
  2442.                       // change states 
  2443.                       lights[index].state = -lights[index].state;               
  2444.  
  2445.                       // update color
  2446.                       lpddpal->SetEntries(0,lights[index].color_index,1,&lights[index].off_color);
  2447.  
  2448.                       } // end if
  2449.                    } // end else if
  2450.                  
  2451.                 } // end for index
  2452.  
  2453.             } break;
  2454.  
  2455.        default: break;
  2456.  
  2457.        } // end switch
  2458.  
  2459. // return success
  2460. return(1);
  2461.  
  2462. } // end Blink_Colors
  2463.  
  2464. ///////////////////////////////////////////////////////////
  2465.  
  2466. int Draw_Text_GDI(char *text, int x,int y,COLORREF color, LPDIRECTDRAWSURFACE4 lpdds)
  2467. {
  2468. // this function draws the sent text on the sent surface 
  2469. // using color index as the color in the palette
  2470.  
  2471. HDC xdc; // the working dc
  2472.  
  2473. // get the dc from surface
  2474. if (FAILED(lpdds->GetDC(&xdc)))
  2475.    return(0);
  2476.  
  2477. // set the colors for the text up
  2478. SetTextColor(xdc,color);
  2479.  
  2480. // set background mode to transparent so black isn't copied
  2481. SetBkMode(xdc, TRANSPARENT);
  2482.  
  2483. // draw the text a
  2484. TextOut(xdc,x,y,text,strlen(text));
  2485.  
  2486. // release the dc
  2487. lpdds->ReleaseDC(xdc);
  2488.  
  2489. // return success
  2490. return(1);
  2491. } // end Draw_Text_GDI
  2492.  
  2493. ///////////////////////////////////////////////////////////
  2494.  
  2495. int Draw_Text_GDI(char *text, int x,int y,int color, LPDIRECTDRAWSURFACE4 lpdds)
  2496. {
  2497. // this function draws the sent text on the sent surface 
  2498. // using color index as the color in the palette
  2499.  
  2500. HDC xdc; // the working dc
  2501.  
  2502. // get the dc from surface
  2503. if (FAILED(lpdds->GetDC(&xdc)))
  2504.    return(0);
  2505.  
  2506. // set the colors for the text up
  2507. SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue) );
  2508.  
  2509. // set background mode to transparent so black isn't copied
  2510. SetBkMode(xdc, TRANSPARENT);
  2511.  
  2512. // draw the text a
  2513. TextOut(xdc,x,y,text,strlen(text));
  2514.  
  2515. // release the dc
  2516. lpdds->ReleaseDC(xdc);
  2517.  
  2518. // return success
  2519. return(1);
  2520. } // end Draw_Text_GDI
  2521.  
  2522. ///////////////////////////////////////////////////////////
  2523.  
  2524. int Open_Error_File(char *filename)
  2525. {
  2526. // this function opens the output error file
  2527.  
  2528. FILE *fp_temp; // temporary file
  2529.  
  2530. // test if this file is valid
  2531. if ((fp_temp = fopen(filename,"w"))==NULL)
  2532.    return(0);
  2533.  
  2534. // close old file if there was one
  2535. if (fp_error)
  2536.    Close_Error_File();
  2537.  
  2538. // assign new file
  2539.  
  2540. fp_error = fp_temp;
  2541.  
  2542. // write out header
  2543. Write_Error("\nOpening Error Output File (%s):\n",filename);
  2544.  
  2545. // return success
  2546. return(1);
  2547.  
  2548. } // end Open_Error_File
  2549.  
  2550. ///////////////////////////////////////////////////////////
  2551.  
  2552. int Close_Error_File(void)
  2553. {
  2554. // this function closes the error file
  2555.  
  2556. if (fp_error)
  2557.     {
  2558.     // write close file string
  2559.     Write_Error("\nClosing Error Output File.");
  2560.  
  2561.     // close the file handle
  2562.     fclose(fp_error);
  2563.     fp_error = NULL;
  2564.  
  2565.     // return success
  2566.     return(1);
  2567.     } // end if
  2568. else
  2569.    return(0);
  2570.  
  2571. } // end Close_Error_File
  2572.  
  2573. ///////////////////////////////////////////////////////////
  2574.  
  2575. int Write_Error(char *string, ...)
  2576. {
  2577. // this function prints out the error string to the error file
  2578.  
  2579. char buffer[80]; // working buffer
  2580.  
  2581. va_list arglist; // variable argument list
  2582.  
  2583. // make sure both the error file and string are valid
  2584. if (!string || !fp_error)
  2585.    return(0);
  2586.  
  2587. // print out the string using the variable number of arguments on stack
  2588. va_start(arglist,string);
  2589. vsprintf(buffer,string,arglist);
  2590. va_end(arglist);
  2591.  
  2592. // write string to file
  2593. fprintf(fp_error,buffer);
  2594.  
  2595. // return success
  2596. return(1);
  2597. } // end Write_Error
  2598.  
  2599. ///////////////////////////////////////////////////////////////////////////////
  2600.  
  2601. int Create_Bitmap(BITMAP_IMAGE_PTR image, int x, int y, int width, int height, int bpp)
  2602. {
  2603. // this function is used to intialize a bitmap, 8 or 16 bit
  2604.  
  2605. // allocate the memory
  2606. if (!(image->buffer = (UCHAR *)malloc(width*height*(bpp>>3))))
  2607.    return(0);
  2608.  
  2609. // initialize variables
  2610. image->state     = BITMAP_STATE_ALIVE;
  2611. image->attr      = 0;
  2612. image->width     = width;
  2613. image->height    = height;
  2614. image->bpp       = bpp;
  2615. image->x         = x;
  2616. image->y         = y;
  2617. image->num_bytes = width*height*(bpp>>3);
  2618.  
  2619. // clear memory out
  2620. memset(image->buffer,0,width*height*(bpp>>3));
  2621.  
  2622. // return success
  2623. return(1);
  2624.  
  2625. } // end Create_Bitmap
  2626.  
  2627. ///////////////////////////////////////////////////////////////////////////////
  2628.  
  2629. int Destroy_Bitmap(BITMAP_IMAGE_PTR image)
  2630. {
  2631. // this function releases the memory associated with a bitmap
  2632.  
  2633. if (image && image->buffer)
  2634.    {
  2635.    // free memory and reset vars
  2636.    free(image->buffer);
  2637.  
  2638.    // set all vars in structure to 0
  2639.    memset(image,0,sizeof(BITMAP_IMAGE));
  2640.  
  2641.    // return success
  2642.    return(1);
  2643.  
  2644.    } // end if
  2645. else  // invalid entry pointer of the object wasn't initialized
  2646.    return(0);
  2647.  
  2648. } // end Destroy_Bitmap
  2649.  
  2650. ///////////////////////////////////////////////////////////
  2651.  
  2652. int Draw_Bitmap(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
  2653. {
  2654. // this function draws the bitmap onto the destination memory surface
  2655. // if transparent is 1 then color 0 (8bit) or 0.0.0 (16bit) will be transparent
  2656. // note this function does NOT clip, so be carefull!!!
  2657.  
  2658. // test if this bitmap is loaded
  2659. if (!(source_bitmap->attr & BITMAP_ATTR_LOADED))
  2660.    return(0);
  2661.  
  2662.     UCHAR *dest_addr,   // starting address of bitmap in destination
  2663.           *source_addr; // starting adddress of bitmap data in source
  2664.  
  2665.     UCHAR pixel;        // used to hold pixel value
  2666.  
  2667.     int index,          // looping vars
  2668.         pixel_x;
  2669.  
  2670.    // compute starting destination address
  2671.    dest_addr = dest_buffer + source_bitmap->y*lpitch + source_bitmap->x;
  2672.  
  2673.    // compute the starting source address
  2674.    source_addr = source_bitmap->buffer;
  2675.  
  2676.    // is this bitmap transparent
  2677.    if (transparent)
  2678.    {
  2679.    // copy each line of bitmap into destination with transparency
  2680.    for (index=0; index<source_bitmap->height; index++)
  2681.        {
  2682.        // copy the memory
  2683.        for (pixel_x=0; pixel_x<source_bitmap->width; pixel_x++)
  2684.            {
  2685.            if ((pixel = source_addr[pixel_x])!=0)
  2686.                dest_addr[pixel_x] = pixel;
  2687.  
  2688.            } // end if
  2689.  
  2690.        // advance all the pointers
  2691.        dest_addr   += lpitch;
  2692.        source_addr += source_bitmap->width;
  2693.  
  2694.        } // end for index
  2695.    } // end if
  2696.    else
  2697.       {
  2698.       // non-transparent version
  2699.       // copy each line of bitmap into destination
  2700.  
  2701.       for (index=0; index < source_bitmap->height; index++)
  2702.           {
  2703.           // copy the memory
  2704.           memcpy(dest_addr, source_addr, source_bitmap->width);
  2705.  
  2706.           // advance all the pointers
  2707.           dest_addr   += lpitch;
  2708.           source_addr += source_bitmap->width;
  2709.  
  2710.           } // end for index
  2711.  
  2712.        } // end else
  2713.  
  2714.    // return success
  2715.    return(1);
  2716.  
  2717. } // end Draw_Bitmap
  2718.  
  2719. ///////////////////////////////////////////////////////////////
  2720.  
  2721. int Draw_Bitmap16(BITMAP_IMAGE_PTR source_bitmap,UCHAR *dest_buffer, int lpitch, int transparent)
  2722. {
  2723. // this function draws the bitmap onto the destination memory surface
  2724. // if transparent is 1 then color 0 (8bit) or 0.0.0 (16bit) will be transparent
  2725. // note this function does NOT clip, so be carefull!!!
  2726.  
  2727. // test if this bitmap is loaded
  2728. if (!(source_bitmap->attr & BITMAP_ATTR_LOADED))
  2729.    return(0);
  2730.  
  2731.    USHORT *dest_addr,   // starting address of bitmap in destination
  2732.           *source_addr; // starting adddress of bitmap data in source
  2733.  
  2734.    USHORT pixel;        // used to hold pixel value
  2735.  
  2736.    int index,           // looping vars
  2737.        pixel_x,
  2738.        lpitch_2 = lpitch >> 1; // lpitch in USHORT terms
  2739.  
  2740.    // compute starting destination address
  2741.    dest_addr = ((USHORT *)dest_buffer) + source_bitmap->y*lpitch_2 + source_bitmap->x;
  2742.  
  2743.    // compute the starting source address
  2744.    source_addr = (USHORT *)source_bitmap->buffer;
  2745.  
  2746.    // is this bitmap transparent
  2747.    if (transparent)
  2748.    {
  2749.    // copy each line of bitmap into destination with transparency
  2750.    for (index=0; index<source_bitmap->height; index++)
  2751.        {
  2752.        // copy the memory
  2753.        for (pixel_x=0; pixel_x<source_bitmap->width; pixel_x++)
  2754.            {
  2755.            if ((pixel = source_addr[pixel_x])!=0)
  2756.                dest_addr[pixel_x] = pixel;
  2757.  
  2758.            } // end if
  2759.  
  2760.        // advance all the pointers
  2761.        dest_addr   += lpitch_2;
  2762.        source_addr += source_bitmap->width;
  2763.  
  2764.        } // end for index
  2765.    } // end if
  2766.    else
  2767.       {
  2768.       // non-transparent version
  2769.       // copy each line of bitmap into destination
  2770.  
  2771.       int source_bytes_per_line = source_bitmap->width*2;
  2772.  
  2773.       for (index=0; index < source_bitmap->height; index++)
  2774.           {
  2775.           // copy the memory
  2776.           memcpy(dest_addr, source_addr, source_bytes_per_line);
  2777.  
  2778.           // advance all the pointers
  2779.           dest_addr   += lpitch_2;
  2780.           source_addr += source_bitmap->width;
  2781.  
  2782.           } // end for index
  2783.  
  2784.       } // end else
  2785.  
  2786.    // return success
  2787.    return(1);
  2788.  
  2789. } // end Draw_Bitmap16
  2790.  
  2791. ///////////////////////////////////////////////////////////////////////////////
  2792.  
  2793. int Load_Image_Bitmap(BITMAP_IMAGE_PTR image,  // bitmap image to load with data
  2794.                       BITMAP_FILE_PTR bitmap,  // bitmap to scan image data from
  2795.                       int cx,int cy,   // cell or absolute pos. to scan image from
  2796.                       int mode)        // if 0 then cx,cy is cell position, else 
  2797.                                        // cx,cy are absolute coords
  2798. {
  2799. // this function extracts a bitmap out of a bitmap file
  2800.  
  2801. // is this a valid bitmap
  2802. if (!image)
  2803.    return(0);
  2804.  
  2805. UCHAR *source_ptr,   // working pointers
  2806.       *dest_ptr;
  2807.  
  2808. // test the mode of extraction, cell based or absolute
  2809. if (mode==BITMAP_EXTRACT_MODE_CELL)
  2810.    {
  2811.    // re-compute x,y
  2812.    cx = cx*(image->width+1) + 1;
  2813.    cy = cy*(image->height+1) + 1;
  2814.    } // end if
  2815.  
  2816. // extract bitmap data
  2817. source_ptr = bitmap->buffer +
  2818.       cy*bitmap->bitmapinfoheader.biWidth+cx;
  2819.  
  2820. // assign a pointer to the bimap image
  2821. dest_ptr = (UCHAR *)image->buffer;
  2822.  
  2823. // iterate thru each scanline and copy bitmap
  2824. for (int index_y=0; index_y<image->height; index_y++)
  2825.     {
  2826.     // copy next line of data to destination
  2827.     memcpy(dest_ptr, source_ptr,image->width);
  2828.  
  2829.     // advance pointers
  2830.     dest_ptr   += image->width;
  2831.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  2832.     } // end for index_y
  2833.  
  2834. // set state to loaded
  2835. image->attr |= BITMAP_ATTR_LOADED;
  2836.  
  2837. // return success
  2838. return(1);
  2839.  
  2840. } // end Load_Image_Bitmap
  2841.  
  2842. ///////////////////////////////////////////////////////////
  2843.  
  2844. int Load_Image_Bitmap16(BITMAP_IMAGE_PTR image,  // bitmap image to load with data
  2845.                         BITMAP_FILE_PTR bitmap,  // bitmap to scan image data from
  2846.                         int cx,int cy,   // cell or absolute pos. to scan image from
  2847.                         int mode)        // if 0 then cx,cy is cell position, else 
  2848.                                        // cx,cy are absolute coords
  2849. {
  2850. // this function extracts a 16-bit bitmap out of a 16-bit bitmap file
  2851.  
  2852. // is this a valid bitmap
  2853. if (!image)
  2854.    return(0);
  2855.  
  2856. // must be a 16bit bitmap
  2857. USHORT *source_ptr,   // working pointers
  2858.        *dest_ptr;
  2859.  
  2860. // test the mode of extraction, cell based or absolute
  2861. if (mode==BITMAP_EXTRACT_MODE_CELL)
  2862.    {
  2863.    // re-compute x,y
  2864.    cx = cx*(image->width+1) + 1;
  2865.    cy = cy*(image->height+1) + 1;
  2866.    } // end if
  2867.  
  2868. // extract bitmap data
  2869. source_ptr = (USHORT *)bitmap->buffer + 
  2870.              cy*bitmap->bitmapinfoheader.biWidth+cx;
  2871.  
  2872. // assign a pointer to the bimap image
  2873. dest_ptr = (USHORT *)image->buffer;
  2874.  
  2875. int bytes_per_line = image->width*2;
  2876.  
  2877. // iterate thru each scanline and copy bitmap
  2878. for (int index_y=0; index_y < image->height; index_y++)
  2879.     {
  2880.     // copy next line of data to destination
  2881.     memcpy(dest_ptr, source_ptr,bytes_per_line);
  2882.  
  2883.     // advance pointers
  2884.     dest_ptr   += image->width;
  2885.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  2886.     } // end for index_y
  2887.  
  2888. // set state to loaded
  2889. image->attr |= BITMAP_ATTR_LOADED;
  2890.  
  2891. // return success
  2892. return(1);
  2893.  
  2894. } // end Load_Image_Bitmap16
  2895.  
  2896. ///////////////////////////////////////////////////////////
  2897.  
  2898.  
  2899. ///////////////////////////////////////////////////////////
  2900.  
  2901. int Scroll_Bitmap(void)
  2902. {
  2903. // this function scrolls a bitmap
  2904. // not implemented
  2905.  
  2906. // return success
  2907. return(1);
  2908. } // end Scroll_Bitmap
  2909. ///////////////////////////////////////////////////////////
  2910.  
  2911. int Copy_Bitmap(void)
  2912. {
  2913. // this function copies a bitmap from one source to another
  2914. // not implemented
  2915.  
  2916.  
  2917. // return success
  2918. return(1);
  2919. } // end Copy_Bitmap
  2920.  
  2921. ///////////////////////////////////////////////////////////
  2922.  
  2923. int Load_Bitmap_File(BITMAP_FILE_PTR bitmap, char *filename)
  2924. {
  2925. // this function opens a bitmap file and loads the data into bitmap
  2926.  
  2927. int file_handle,  // the file handle
  2928.     index;        // looping index
  2929.  
  2930. UCHAR   *temp_buffer = NULL; // used to convert 24 bit images to 16 bit
  2931. OFSTRUCT file_data;          // the file data information
  2932.  
  2933. // open the file if it exists
  2934. if ((file_handle = OpenFile(filename,&file_data,OF_READ))==-1)
  2935.    return(0);
  2936.  
  2937. // now load the bitmap file header
  2938. _lread(file_handle, &bitmap->bitmapfileheader,sizeof(BITMAPFILEHEADER));
  2939.  
  2940. // test if this is a bitmap file
  2941. if (bitmap->bitmapfileheader.bfType!=BITMAP_ID)
  2942.    {
  2943.    // close the file
  2944.    _lclose(file_handle);
  2945.  
  2946.    // return error
  2947.    return(0);
  2948.    } // end if
  2949.  
  2950. // now we know this is a bitmap, so read in all the sections
  2951.  
  2952. // first the bitmap infoheader
  2953.  
  2954. // now load the bitmap file header
  2955. _lread(file_handle, &bitmap->bitmapinfoheader,sizeof(BITMAPINFOHEADER));
  2956.  
  2957. // now load the color palette if there is one
  2958. if (bitmap->bitmapinfoheader.biBitCount == 8)
  2959.    {
  2960.    _lread(file_handle, &bitmap->palette,MAX_COLORS_PALETTE*sizeof(PALETTEENTRY));
  2961.  
  2962.    // now set all the flags in the palette correctly and fix the reversed 
  2963.    // BGR RGBQUAD data format
  2964.    for (index=0; index < MAX_COLORS_PALETTE; index++)
  2965.        {
  2966.        // reverse the red and green fields
  2967.        int temp_color                = bitmap->palette[index].peRed;
  2968.        bitmap->palette[index].peRed  = bitmap->palette[index].peBlue;
  2969.        bitmap->palette[index].peBlue = temp_color;
  2970.        
  2971.        // always set the flags word to this
  2972.        bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
  2973.        } // end for index
  2974.  
  2975.     } // end if
  2976.  
  2977. // finally the image data itself
  2978. _lseek(file_handle,-(int)(bitmap->bitmapinfoheader.biSizeImage),SEEK_END);
  2979.  
  2980. // now read in the image
  2981. if (bitmap->bitmapinfoheader.biBitCount==8 || bitmap->bitmapinfoheader.biBitCount==16) 
  2982.    {
  2983.    // delete the last image if there was one
  2984.    if (bitmap->buffer)
  2985.        free(bitmap->buffer);
  2986.  
  2987.    // allocate the memory for the image
  2988.    if (!(bitmap->buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  2989.       {
  2990.       // close the file
  2991.       _lclose(file_handle);
  2992.  
  2993.       // return error
  2994.       return(0);
  2995.       } // end if
  2996.  
  2997.    // now read it in
  2998.    _lread(file_handle,bitmap->buffer,bitmap->bitmapinfoheader.biSizeImage);
  2999.  
  3000.    } // end if
  3001. else
  3002. if (bitmap->bitmapinfoheader.biBitCount==24)
  3003.    {
  3004.    // allocate temporary buffer to load 24 bit image
  3005.    if (!(temp_buffer = (UCHAR *)malloc(bitmap->bitmapinfoheader.biSizeImage)))
  3006.       {
  3007.       // close the file
  3008.       _lclose(file_handle);
  3009.  
  3010.       // return error
  3011.       return(0);
  3012.       } // end if
  3013.    
  3014.    // allocate final 16 bit storage buffer
  3015.    if (!(bitmap->buffer=(UCHAR *)malloc(2*bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight)))
  3016.       {
  3017.       // close the file
  3018.       _lclose(file_handle);
  3019.  
  3020.       // release working buffer
  3021.       free(temp_buffer);
  3022.  
  3023.       // return error
  3024.       return(0);
  3025.       } // end if
  3026.  
  3027.    // now read the file in
  3028.    _lread(file_handle,temp_buffer,bitmap->bitmapinfoheader.biSizeImage);
  3029.  
  3030.    // now convert each 24 bit RGB value into a 16 bit value
  3031.    for (index=0; index < bitmap->bitmapinfoheader.biWidth*bitmap->bitmapinfoheader.biHeight; index++)
  3032.        {
  3033.        // build up 16 bit color word
  3034.        USHORT color;
  3035.        
  3036.        // build pixel based on format of directdraw surface
  3037.        if (dd_pixel_format==DD_PIXEL_FORMAT555)
  3038.            {
  3039.            // extract RGB components (in BGR order), note the scaling
  3040.            UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
  3041.                  green = (temp_buffer[index*3 + 1] >> 3),
  3042.                  red   = (temp_buffer[index*3 + 2] >> 3); 
  3043.            // use the 555 macro
  3044.            color = _RGB16BIT555(red,green,blue);
  3045.            } // end if 555
  3046.        else
  3047.        if (dd_pixel_format==DD_PIXEL_FORMAT565) 
  3048.           {
  3049.           // extract RGB components (in BGR order), note the scaling
  3050.            UCHAR blue  = (temp_buffer[index*3 + 0] >> 3),
  3051.                  green = (temp_buffer[index*3 + 1] >> 3),
  3052.                  red   = (temp_buffer[index*3 + 2] >> 3);
  3053.  
  3054.            // use the 565 macro
  3055.            color = _RGB16BIT565(red,green,blue);
  3056.  
  3057.           } // end if 565
  3058.  
  3059.        // write color to buffer
  3060.        ((USHORT *)bitmap->buffer)[index] = color;
  3061.  
  3062.        } // end for index
  3063.  
  3064.    // finally write out the correct number of bits
  3065.    bitmap->bitmapinfoheader.biBitCount=16;
  3066.  
  3067.    // release working buffer
  3068.    free(temp_buffer);
  3069.  
  3070.    } // end if 24 bit
  3071. else
  3072.    {
  3073.    // serious problem
  3074.    return(0);
  3075.  
  3076.    } // end else
  3077.  
  3078. #if 0
  3079. // write the file info out 
  3080. printf("\nfilename:%s \nsize=%d \nwidth=%d \nheight=%d \nbitsperpixel=%d \ncolors=%d \nimpcolors=%d",
  3081.         filename,
  3082.         bitmap->bitmapinfoheader.biSizeImage,
  3083.         bitmap->bitmapinfoheader.biWidth,
  3084.         bitmap->bitmapinfoheader.biHeight,
  3085.         bitmap->bitmapinfoheader.biBitCount,
  3086.         bitmap->bitmapinfoheader.biClrUsed,
  3087.         bitmap->bitmapinfoheader.biClrImportant);
  3088. #endif
  3089.  
  3090. // close the file
  3091. _lclose(file_handle);
  3092.  
  3093. // flip the bitmap
  3094. Flip_Bitmap(bitmap->buffer, 
  3095.             bitmap->bitmapinfoheader.biWidth*(bitmap->bitmapinfoheader.biBitCount/8), 
  3096.             bitmap->bitmapinfoheader.biHeight);
  3097.  
  3098. // return success
  3099. return(1);
  3100.  
  3101. } // end Load_Bitmap_File
  3102.  
  3103. ///////////////////////////////////////////////////////////
  3104.  
  3105. int Unload_Bitmap_File(BITMAP_FILE_PTR bitmap)
  3106. {
  3107. // this function releases all memory associated with "bitmap"
  3108. if (bitmap->buffer)
  3109.    {
  3110.    // release memory
  3111.    free(bitmap->buffer);
  3112.  
  3113.    // reset pointer
  3114.    bitmap->buffer = NULL;
  3115.  
  3116.    } // end if
  3117.  
  3118. // return success
  3119. return(1);
  3120.  
  3121. } // end Unload_Bitmap_File
  3122.  
  3123. ///////////////////////////////////////////////////////////
  3124.  
  3125. int Flip_Bitmap(UCHAR *image, int bytes_per_line, int height)
  3126. {
  3127. // this function is used to flip bottom-up .BMP images
  3128.  
  3129. UCHAR *buffer; // used to perform the image processing
  3130. int index;     // looping index
  3131.  
  3132. // allocate the temporary buffer
  3133. if (!(buffer = (UCHAR *)malloc(bytes_per_line*height)))
  3134.    return(0);
  3135.  
  3136. // copy image to work area
  3137. memcpy(buffer,image,bytes_per_line*height);
  3138.  
  3139. // flip vertically
  3140. for (index=0; index < height; index++)
  3141.     memcpy(&image[((height-1) - index)*bytes_per_line],
  3142.            &buffer[index*bytes_per_line], bytes_per_line);
  3143.  
  3144. // release the memory
  3145. free(buffer);
  3146.  
  3147. // return success
  3148. return(1);
  3149.  
  3150. } // end Flip_Bitmap
  3151.  
  3152. ///////////////////////////////////////////////////////////
  3153.  
  3154. void HLine(int x1,int x2,int y,int color, UCHAR *vbuffer, int lpitch)
  3155. {
  3156. // draw a horizontal line using the memset function
  3157.  
  3158. int temp; // used for temporary storage during endpoint swap
  3159.  
  3160. // perform trivial rejections
  3161. if (y > max_clip_y || y < min_clip_y)
  3162.    return;
  3163.  
  3164. // sort x1 and x2, so that x2 > x1
  3165. if (x1>x2)
  3166.    {
  3167.    temp = x1;
  3168.    x1   = x2;
  3169.    x2   = temp;
  3170.    } // end swap
  3171.  
  3172. // perform trivial rejections
  3173. if (x1 > max_clip_x || x2 < min_clip_x)
  3174.    return;
  3175.  
  3176. // now clip
  3177. x1 = ((x1 < min_clip_x) ? min_clip_x : x1);
  3178. x2 = ((x2 > max_clip_x) ? max_clip_x : x2);
  3179.  
  3180. // draw the row of pixels
  3181. memset((UCHAR *)(vbuffer+(y*lpitch)+x1),
  3182.        (UCHAR)color,x2-x1+1);
  3183.  
  3184. } // end HLine
  3185.  
  3186. //////////////////////////////////////////////////////////////////////////////
  3187.  
  3188. void VLine(int y1,int y2,int x,int color,UCHAR *vbuffer, int lpitch)
  3189. {
  3190. // draw a vertical line, note that a memset function can no longer be
  3191. // used since the pixel addresses are no longer contiguous in memory
  3192. // note that the end points of the line must be on the screen
  3193.  
  3194. UCHAR *start_offset; // starting memory offset of line
  3195.  
  3196. int index, // loop index
  3197.     temp;  // used for temporary storage during swap
  3198.  
  3199.  
  3200. // perform trivial rejections
  3201. if (x > max_clip_x || x < min_clip_x)
  3202.    return;
  3203.  
  3204. // make sure y2 > y1
  3205. if (y1>y2)
  3206.    {
  3207.    temp = y1;
  3208.    y1   = y2;
  3209.    y2   = temp;
  3210.    } // end swap
  3211.  
  3212. // perform trivial rejections
  3213. if (y1 > max_clip_y || y2 < min_clip_y)
  3214.    return;
  3215.  
  3216. // now clip
  3217. y1 = ((y1 < min_clip_y) ? min_clip_y : y1);
  3218. y2 = ((y2 > max_clip_y) ? max_clip_y : y2);
  3219.  
  3220. // compute starting position
  3221. start_offset = vbuffer + (y1*lpitch) + x;
  3222.  
  3223. // draw line one pixel at a time
  3224. for (index=0; index<=y2-y1; index++)
  3225.     {
  3226.     // set the pixel
  3227.     *start_offset = (UCHAR)color;
  3228.  
  3229.     // move downward to next line
  3230.     start_offset+=lpitch;
  3231.  
  3232.     } // end for index
  3233.  
  3234. } // end VLine
  3235.  
  3236. ///////////////////////////////////////////////////////////
  3237.  
  3238. void Screen_Transitions(int effect, UCHAR *vbuffer, int lpitch)
  3239. {
  3240. // this function can be called to perform a myraid of screen transitions
  3241. // to the destination buffer, make sure to save and restore the palette
  3242. // when performing color transitions
  3243.  
  3244. int pal_reg;         // used as loop counter
  3245. int index;           // used as loop counter
  3246. int red,green,blue;           // used in fad algorithm
  3247.  
  3248. PALETTEENTRY color;              // temporary color
  3249. PALETTEENTRY work_palette[MAX_COLORS_PALETTE];  // used as a working palette
  3250. PALETTEENTRY work_color;         // used in color algorithms
  3251.  
  3252. // test which screen effect is being selected
  3253. switch(effect)
  3254.       {
  3255.       case SCREEN_DARKNESS:
  3256.            {
  3257.            // fade to black
  3258.  
  3259.            for (index=0; index<80; index++)
  3260.                {
  3261.                // get the palette 
  3262.                Save_Palette(work_palette);
  3263.  
  3264.                // process each color
  3265.                for (pal_reg=1; pal_reg<MAX_COLORS_PALETTE; pal_reg++)
  3266.                    {
  3267.                    // get the entry data
  3268.                    color = work_palette[pal_reg];
  3269.  
  3270.                    // test if this color register is already black
  3271.                    if (color.peRed > 4) color.peRed-=3;
  3272.                    else
  3273.                       color.peRed = 0;
  3274.  
  3275.                    if (color.peGreen > 4) color.peGreen-=3;
  3276.                    else
  3277.                       color.peGreen = 0;
  3278.  
  3279.                    if (color.peBlue  > 4) color.peBlue-=3;
  3280.                    else
  3281.                       color.peBlue = 0;
  3282.  
  3283.                    // set the color to a diminished intensity
  3284.                    work_palette[pal_reg] = color;
  3285.  
  3286.                    } // end for pal_reg
  3287.  
  3288.                // write the palette back out
  3289.                Set_Palette(work_palette);
  3290.  
  3291.                // wait a bit
  3292.                
  3293.                Start_Clock(); Wait_Clock(12);
  3294.                
  3295.                } // end for index
  3296.  
  3297.            } break;
  3298.  
  3299.       case SCREEN_WHITENESS:
  3300.            {
  3301.            // fade to white
  3302.            for (index=0; index<64; index++)
  3303.                {
  3304.                // get the palette 
  3305.                Save_Palette(work_palette);
  3306.  
  3307.                // loop thru all palette registers
  3308.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  3309.                    {
  3310.                    // get the entry data
  3311.                    color = work_palette[pal_reg];
  3312.  
  3313.                    // make 32 bit copy of color
  3314.                    red   = color.peRed;
  3315.                    green = color.peGreen;
  3316.                    blue  = color.peBlue; 
  3317.  
  3318.                    if ((red+=4) >=255)
  3319.                       red=255;
  3320.  
  3321.                    if ((green+=4) >=255)
  3322.                       green=255;
  3323.  
  3324.                    if ((blue+=4) >=255)
  3325.                       blue=255;
  3326.                           
  3327.                    // store colors back
  3328.                    color.peRed   = red;
  3329.                    color.peGreen = green;
  3330.                    color.peBlue  = blue;
  3331.  
  3332.                    // set the color to a diminished intensity
  3333.                    work_palette[pal_reg] = color;
  3334.                    
  3335.                    } // end for pal_reg
  3336.  
  3337.                // write the palette back out
  3338.                Set_Palette(work_palette);
  3339.  
  3340.                // wait a bit
  3341.                
  3342.                Start_Clock(); Wait_Clock(12);
  3343.  
  3344.                } // end for index
  3345.  
  3346.            } break;
  3347.  
  3348.       case SCREEN_REDNESS:
  3349.            {
  3350.            // fade to red
  3351.  
  3352.            for (index=0; index<64; index++)
  3353.                {
  3354.                // get the palette 
  3355.                Save_Palette(work_palette);
  3356.                
  3357.                // loop thru all palette registers
  3358.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  3359.                    {
  3360.                    // get the entry data
  3361.                    color = work_palette[pal_reg];
  3362.  
  3363.                    // make 32 bit copy of color
  3364.                    red   = color.peRed;
  3365.                    green = color.peGreen;
  3366.                    blue  = color.peBlue; 
  3367.  
  3368.                    if ((red+=6) >=255)
  3369.                       red=255; 
  3370.  
  3371.                    if ((green-=4) < 0)
  3372.                       green=0;
  3373.  
  3374.                    if ((blue-=4) < 0)
  3375.                       blue=0;
  3376.                           
  3377.                    // store colors back
  3378.                    color.peRed   = red;
  3379.                    color.peGreen = green;
  3380.                    color.peBlue  = blue;
  3381.                   
  3382.                    // set the color to a diminished intensity
  3383.                    work_palette[pal_reg] = color;
  3384.  
  3385.                    } // end for pal_reg
  3386.  
  3387.                // write the palette back out
  3388.                Set_Palette(work_palette);
  3389.  
  3390.                // wait a bit
  3391.                
  3392.                Start_Clock(); Wait_Clock(12);
  3393.  
  3394.                } // end for index
  3395.  
  3396.            } break;
  3397.  
  3398.       case SCREEN_BLUENESS:
  3399.            {
  3400.            // fade to blue
  3401.  
  3402.            for (index=0; index<64; index++)
  3403.                {
  3404.                // get the palette 
  3405.                Save_Palette(work_palette);
  3406.                
  3407.                // loop thru all palette registers
  3408.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  3409.                    {
  3410.                    // get the entry data
  3411.                    color = work_palette[pal_reg];
  3412.  
  3413.                    // make 32 bit copy of color
  3414.                    red   = color.peRed;
  3415.                    green = color.peGreen;
  3416.                    blue  = color.peBlue; 
  3417.  
  3418.                    if ((red-=4) < 0)
  3419.                       red=0;
  3420.  
  3421.                    if ((green-=4) < 0)
  3422.                       green=0;
  3423.  
  3424.                    if ((blue+=6) >=255)
  3425.                       blue=255;
  3426.                           
  3427.                    // store colors back
  3428.                    color.peRed   = red;
  3429.                    color.peGreen = green;
  3430.                    color.peBlue  = blue;
  3431.                   
  3432.                    // set the color to a diminished intensity
  3433.                    work_palette[pal_reg] = color;
  3434.  
  3435.                    } // end for pal_reg
  3436.  
  3437.                // write the palette back out
  3438.                Set_Palette(work_palette);
  3439.  
  3440.                // wait a bit
  3441.                
  3442.                Start_Clock(); Wait_Clock(12);
  3443.  
  3444.                } // end for index
  3445.  
  3446.            } break;
  3447.  
  3448.       case SCREEN_GREENNESS:
  3449.            {
  3450.            // fade to green
  3451.            for (index=0; index<64; index++)
  3452.                {
  3453.                // get the palette 
  3454.                Save_Palette(work_palette);
  3455.  
  3456.                // loop thru all palette registers
  3457.                for (pal_reg=0; pal_reg < MAX_COLORS_PALETTE; pal_reg++)
  3458.                    {
  3459.                    // get the entry data
  3460.                    color = work_palette[pal_reg];                  
  3461.  
  3462.                    // make 32 bit copy of color
  3463.                    red   = color.peRed;
  3464.                    green = color.peGreen;
  3465.                    blue  = color.peBlue; 
  3466.  
  3467.                    if ((red-=4) < 0)
  3468.                       red=0;
  3469.  
  3470.                    if ((green+=6) >=255)
  3471.                       green=255;
  3472.  
  3473.                    if ((blue-=4) < 0)
  3474.                       blue=0;
  3475.                           
  3476.                    // store colors back
  3477.                    color.peRed   = red;
  3478.                    color.peGreen = green;
  3479.                    color.peBlue  = blue;
  3480.  
  3481.                    // set the color to a diminished intensity
  3482.                    work_palette[pal_reg] = color; 
  3483.  
  3484.                    } // end for pal_reg
  3485.  
  3486.                // write the palette back out
  3487.                Set_Palette(work_palette);
  3488.  
  3489.                // wait a bit
  3490.                
  3491.                Start_Clock(); Wait_Clock(12);
  3492.  
  3493.  
  3494.                } // end for index
  3495.  
  3496.            } break;
  3497.  
  3498.       case SCREEN_SWIPE_X:
  3499.            {
  3500.            // do a screen wipe from right to left, left to right
  3501.            for (index=0; index < (screen_width/2); index+=2)
  3502.                {
  3503.                // use this as a 1/70th of second time delay
  3504.                
  3505.                Start_Clock(); Wait_Clock(12);
  3506.  
  3507.                // draw two vertical lines at opposite ends of the screen
  3508.                VLine(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  3509.                VLine(0,(screen_height-1),index,0,vbuffer,lpitch);
  3510.                VLine(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  3511.                VLine(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  3512.  
  3513.                } // end for index
  3514.  
  3515.            } break;
  3516.  
  3517.       case SCREEN_SWIPE_Y:
  3518.            {
  3519.            // do a screen wipe from top to bottom, bottom to top
  3520.            for (index=0; index < (screen_height/2); index+=2)
  3521.                {
  3522.                // use this as a 1/70th of second time delay
  3523.                
  3524.                Start_Clock(); Wait_Clock(12);
  3525.  
  3526.                // draw two horizontal lines at opposite ends of the screen
  3527.                HLine(0,(screen_width-1),(screen_height-1)-index,0,vbuffer,lpitch);
  3528.                HLine(0,(screen_width-1),index,0,vbuffer,lpitch);
  3529.                HLine(0,(screen_width-1),(screen_height-1)-(index+1),0,vbuffer,lpitch);
  3530.                HLine(0,(screen_width-1),index+1,0,vbuffer,lpitch);
  3531.  
  3532.                } // end for index
  3533.  
  3534.  
  3535.             } break;
  3536.  
  3537.       case SCREEN_SCRUNCH:
  3538.            {
  3539.            // do a screen wipe from top to bottom, bottom to top
  3540.            for (index=0; index < (screen_width/2); index+=2)
  3541.                {
  3542.                // use this as a 1/70th of second time delay
  3543.                
  3544.                Start_Clock(); Wait_Clock(12);
  3545.  
  3546.                // draw two horizontal lines at opposite ends of the screen
  3547.                HLine(0,(screen_width-1),(screen_height-1)-index%(screen_height/2),0,vbuffer,lpitch);
  3548.                HLine(0,(screen_width-1),index%(screen_height/2),0,vbuffer,lpitch);
  3549.                HLine(0,(screen_width-1),(screen_height-1)-(index%(screen_height/2)+1),0,vbuffer,lpitch);
  3550.                HLine(0,(screen_width-1),index%(screen_height/2)+1,0,vbuffer,lpitch);
  3551.  
  3552.                // draw two vertical lines at opposite ends of the screen
  3553.                VLine(0,(screen_height-1),(screen_width-1)-index,0,vbuffer,lpitch);
  3554.                VLine(0,(screen_height-1),index,0,vbuffer,lpitch);
  3555.                VLine(0,(screen_height-1),(screen_width-1)-(index+1),0,vbuffer,lpitch);
  3556.                VLine(0,(screen_height-1),index+1,0,vbuffer,lpitch);
  3557.  
  3558.                } // end for index
  3559.  
  3560.            } break;
  3561.  
  3562.  
  3563.       case SCREEN_DISOLVE:
  3564.            {
  3565.            // disolve the screen by plotting zillions of little black dots
  3566.  
  3567.            for (index=0; index<=screen_width*screen_height*4; index++)
  3568.                Draw_Pixel(rand()%screen_width,rand()%screen_height,0,vbuffer,lpitch);
  3569.        
  3570.            } break;
  3571.  
  3572.        default:break;
  3573.  
  3574.       } // end switch
  3575.  
  3576. } // end Screen_Transitions
  3577.  
  3578. //////////////////////////////////////////////////////////////////////////////
  3579.  
  3580. int Collision_Test(int x1, int y1, int w1, int h1, 
  3581.                    int x2, int y2, int w2, int h2) 
  3582. {
  3583. // this function tests if the two rects overlap
  3584.  
  3585. // get the radi of each rect
  3586. int width1  = (w1>>1) - (w1>>3);
  3587. int height1 = (h1>>1) - (h1>>3);
  3588.  
  3589. int width2  = (w2>>1) - (w2>>3);
  3590. int height2 = (h2>>1) - (h2>>3);
  3591.  
  3592. // compute center of each rect
  3593. int cx1 = x1 + width1;
  3594. int cy1 = y1 + height1;
  3595.  
  3596. int cx2 = x2 + width2;
  3597. int cy2 = y2 + height2;
  3598.  
  3599. // compute deltas
  3600. int dx = abs(cx2 - cx1);
  3601. int dy = abs(cy2 - cy1);
  3602.  
  3603. // test if rects overlap
  3604. if (dx < (width1+width2) && dy < (height1+height2))
  3605.    return(1);
  3606. else
  3607. // else no collision
  3608. return(0);
  3609.  
  3610. } // end Collision_Test
  3611.  
  3612. ///////////////////////////////////////////////////////////
  3613.  
  3614. int Color_Scan(int x1, int y1, int x2, int y2, 
  3615.                UCHAR scan_start, UCHAR scan_end,
  3616.                UCHAR *scan_buffer, int scan_lpitch)
  3617. {
  3618. // this function implements a crude collision technique
  3619. // based on scanning for a range of colors within a rectangle
  3620.  
  3621. // clip rectangle
  3622.  
  3623. // x coords first    
  3624. if (x1 >= screen_width)
  3625.    x1=screen_width-1;
  3626. else
  3627. if (x1 < 0)
  3628.    x1=0;
  3629.  
  3630. if (x2 >= screen_width)
  3631.    x2=screen_width-1;
  3632. else
  3633. if (x2 < 0)
  3634.    x2=0;
  3635.  
  3636. // now y-coords
  3637. if (y1 >= screen_height)
  3638.    y1=screen_height-1;
  3639. else
  3640. if (y1 < 0)
  3641.    y1=0;
  3642.  
  3643. if (y2 >= screen_height)
  3644.    y2=screen_height-1;
  3645. else
  3646. if (y2 < 0)
  3647.    y2=0;
  3648.  
  3649. // scan the region
  3650. scan_buffer +=y1*scan_lpitch;
  3651.  
  3652. for (int scan_y=y1; scan_y<=y2; scan_y++)
  3653.     {
  3654.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  3655.         {
  3656.         if (scan_buffer[scan_x] >= scan_start && scan_buffer[scan_x] <= scan_end )
  3657.             return(1);
  3658.         } // end for x
  3659.  
  3660.     // move down a line
  3661.     scan_buffer+=scan_lpitch;
  3662.  
  3663.     } // end for y
  3664.  
  3665. // return failure
  3666. return(0);
  3667.  
  3668. } // end Color_Scan
  3669.  
  3670. ////////////////////////////////////////////////////////////////
  3671.  
  3672. int Color_Scan16(int x1, int y1, int x2, int y2, 
  3673.                USHORT scan_start, USHORT scan_end,
  3674.                UCHAR *scan_buffer, int scan_lpitch)
  3675. {
  3676. // this function implements a crude collision technique
  3677. // based on scanning for a range of colors within a rectangle
  3678. // this is the 16-bit version
  3679. USHORT *scan_buffer2 = (USHORT *)scan_buffer;
  3680.  
  3681. // convert number of bytes per line to number of 16-bit shorts
  3682. scan_lpitch = (scan_lpitch >> 1);
  3683.  
  3684. // clip rectangle
  3685.  
  3686. // x coords first    
  3687. if (x1 >= screen_width)
  3688.    x1=screen_width-1;
  3689. else
  3690. if (x1 < 0)
  3691.    x1=0;
  3692.  
  3693. if (x2 >= screen_width)
  3694.    x2=screen_width-1;
  3695. else
  3696. if (x2 < 0)
  3697.    x2=0;
  3698.  
  3699. // now y-coords
  3700. if (y1 >= screen_height)
  3701.    y1=screen_height-1;
  3702. else
  3703. if (y1 < 0)
  3704.    y1=0;
  3705.  
  3706. if (y2 >= screen_height)
  3707.    y2=screen_height-1;
  3708. else
  3709. if (y2 < 0)
  3710.    y2=0;
  3711.  
  3712. // scan the region
  3713. scan_buffer2 +=y1*scan_lpitch;
  3714.  
  3715. for (int scan_y=y1; scan_y<=y2; scan_y++)
  3716.     {
  3717.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  3718.         {
  3719.         if (scan_buffer[scan_x] >= scan_start && scan_buffer[scan_x] <= scan_end )
  3720.             return(1);
  3721.         } // end for x
  3722.  
  3723.     // move down a line
  3724.     scan_buffer+=scan_lpitch;
  3725.  
  3726.     } // end for y
  3727.  
  3728. // return failure
  3729. return(0);
  3730.  
  3731. } // end Color_Scan16
  3732.  
  3733. ////////////////////////////////////////////////////////////////
  3734.  
  3735. int Scan_Image_Bitmap(BITMAP_FILE_PTR bitmap,     // bitmap file to scan image data from
  3736.                       LPDIRECTDRAWSURFACE4 lpdds, // surface to hold data
  3737.                       int cx,int cy)              // cell to scan image from
  3738. {
  3739. // this function extracts a bitmap out of a bitmap file
  3740.  
  3741. UCHAR *source_ptr,   // working pointers
  3742.       *dest_ptr;
  3743.  
  3744. DDSURFACEDESC2 ddsd;  //  direct draw surface description 
  3745.  
  3746. // get the addr to destination surface memory
  3747.  
  3748. // set size of the structure
  3749. ddsd.dwSize = sizeof(ddsd);
  3750.  
  3751. // lock the display surface
  3752. lpdds->Lock(NULL,
  3753.             &ddsd,
  3754.             DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
  3755.             NULL);
  3756.  
  3757. // compute position to start scanning bits from
  3758. cx = cx*(ddsd.dwWidth+1) + 1;
  3759. cy = cy*(ddsd.dwHeight+1) + 1;
  3760.   
  3761. // extract bitmap data
  3762. source_ptr = bitmap->buffer + cy*bitmap->bitmapinfoheader.biWidth+cx;
  3763.  
  3764. // assign a pointer to the memory surface for manipulation
  3765. dest_ptr = (UCHAR *)ddsd.lpSurface;
  3766.  
  3767. // iterate thru each scanline and copy bitmap
  3768. for (int index_y=0; index_y < ddsd.dwHeight; index_y++)
  3769.     {
  3770.     // copy next line of data to destination
  3771.     memcpy(dest_ptr, source_ptr, ddsd.dwWidth);
  3772.  
  3773.     // advance pointers
  3774.     dest_ptr   += (ddsd.dwWidth);
  3775.     source_ptr += bitmap->bitmapinfoheader.biWidth;
  3776.     } // end for index_y
  3777.  
  3778. // unlock the surface 
  3779. lpdds->Unlock(NULL);
  3780.  
  3781. // return success
  3782. return(1);
  3783.  
  3784. } // end Scan_Image_Bitmap
  3785.  
  3786. //////////////////////////////////////////////////////////////////////////////
  3787.  
  3788. void Draw_Top_Tri(int x1,int y1, 
  3789.                   int x2,int y2, 
  3790.                   int x3,int y3,
  3791.                   int color, 
  3792.                   UCHAR *dest_buffer, int mempitch)
  3793. {
  3794. // this function draws a triangle that has a flat top
  3795.  
  3796. float dx_right,    // the dx/dy ratio of the right edge of line
  3797.       dx_left,     // the dx/dy ratio of the left edge of line
  3798.       xs,xe,       // the starting and ending points of the edges
  3799.       height;      // the height of the triangle
  3800.  
  3801. int temp_x,        // used during sorting as temps
  3802.     temp_y,
  3803.     right,         // used by clipping
  3804.     left;
  3805.  
  3806. // destination address of next scanline
  3807. UCHAR  *dest_addr = NULL;
  3808.  
  3809. // test order of x1 and x2
  3810. if (x2 < x1)
  3811.    {
  3812.    temp_x = x2;
  3813.    x2     = x1;
  3814.    x1     = temp_x;
  3815.    } // end if swap
  3816.  
  3817. // compute delta's
  3818. height = y3-y1;
  3819.  
  3820. dx_left  = (x3-x1)/height;
  3821. dx_right = (x3-x2)/height;
  3822.  
  3823. // set starting points
  3824. xs = (float)x1;
  3825. xe = (float)x2+(float)0.5;
  3826.  
  3827. // perform y clipping
  3828. if (y1 < min_clip_y)
  3829.    {
  3830.    // compute new xs and ys
  3831.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  3832.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  3833.  
  3834.    // reset y1
  3835.    y1=min_clip_y;
  3836.  
  3837.    } // end if top is off screen
  3838.  
  3839. if (y3>max_clip_y)
  3840.    y3=max_clip_y;
  3841.  
  3842. // compute starting address in video memory
  3843. dest_addr = dest_buffer+y1*mempitch;
  3844.  
  3845. // test if x clipping is needed
  3846. if (x1>=min_clip_x && x1<=max_clip_x &&
  3847.     x2>=min_clip_x && x2<=max_clip_x &&
  3848.     x3>=min_clip_x && x3<=max_clip_x)
  3849.     {
  3850.     // draw the triangle
  3851.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  3852.         {
  3853.         memset((UCHAR *)dest_addr+(unsigned int)xs,
  3854.                 color,(unsigned int)(xe-xs+1));
  3855.  
  3856.         // adjust starting point and ending point
  3857.         xs+=dx_left;
  3858.         xe+=dx_right;
  3859.  
  3860.         } // end for
  3861.  
  3862.     } // end if no x clipping needed
  3863. else
  3864.    {
  3865.    // clip x axis with slower version
  3866.  
  3867.    // draw the triangle
  3868.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  3869.        {
  3870.        // do x clip
  3871.        left  = (int)xs;
  3872.        right = (int)xe;
  3873.  
  3874.        // adjust starting point and ending point
  3875.        xs+=dx_left;
  3876.        xe+=dx_right;
  3877.  
  3878.        // clip line
  3879.        if (left < min_clip_x)
  3880.           {
  3881.           left = min_clip_x;
  3882.  
  3883.           if (right < min_clip_x)
  3884.              continue;
  3885.           }
  3886.  
  3887.        if (right > max_clip_x)
  3888.           {
  3889.           right = max_clip_x;
  3890.  
  3891.           if (left > max_clip_x)
  3892.              continue;
  3893.           }
  3894.  
  3895.        memset((UCHAR  *)dest_addr+(unsigned int)left,
  3896.               color,(unsigned int)(right-left+1));
  3897.  
  3898.        } // end for
  3899.  
  3900.    } // end else x clipping needed
  3901.  
  3902. } // end Draw_Top_Tri
  3903.  
  3904. /////////////////////////////////////////////////////////////////////////////
  3905.  
  3906. void Draw_Bottom_Tri(int x1,int y1, 
  3907.                      int x2,int y2, 
  3908.                      int x3,int y3,
  3909.                      int color,
  3910.                      UCHAR *dest_buffer, int mempitch)
  3911. {
  3912. // this function draws a triangle that has a flat bottom
  3913.  
  3914. float dx_right,    // the dx/dy ratio of the right edge of line
  3915.       dx_left,     // the dx/dy ratio of the left edge of line
  3916.       xs,xe,       // the starting and ending points of the edges
  3917.       height;      // the height of the triangle
  3918.  
  3919. int temp_x,        // used during sorting as temps
  3920.     temp_y,
  3921.     right,         // used by clipping
  3922.     left;
  3923.  
  3924. // destination address of next scanline
  3925. UCHAR  *dest_addr;
  3926.  
  3927. // test order of x1 and x2
  3928. if (x3 < x2)
  3929.    {
  3930.    temp_x = x2;
  3931.    x2     = x3;
  3932.    x3     = temp_x;
  3933.    } // end if swap
  3934.  
  3935. // compute delta's
  3936. height = y3-y1;
  3937.  
  3938. dx_left  = (x2-x1)/height;
  3939. dx_right = (x3-x1)/height;
  3940.  
  3941. // set starting points
  3942. xs = (float)x1;
  3943. xe = (float)x1; // +(float)0.5;
  3944.  
  3945. // perform y clipping
  3946. if (y1<min_clip_y)
  3947.    {
  3948.    // compute new xs and ys
  3949.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  3950.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  3951.  
  3952.    // reset y1
  3953.    y1=min_clip_y;
  3954.  
  3955.    } // end if top is off screen
  3956.  
  3957. if (y3>max_clip_y)
  3958.    y3=max_clip_y;
  3959.  
  3960. // compute starting address in video memory
  3961. dest_addr = dest_buffer+y1*mempitch;
  3962.  
  3963. // test if x clipping is needed
  3964. if (x1>=min_clip_x && x1<=max_clip_x &&
  3965.     x2>=min_clip_x && x2<=max_clip_x &&
  3966.     x3>=min_clip_x && x3<=max_clip_x)
  3967.     {
  3968.     // draw the triangle
  3969.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  3970.         {
  3971.         memset((UCHAR  *)dest_addr+(unsigned int)xs,
  3972.                 color,(unsigned int)(xe-xs+1));
  3973.  
  3974.         // adjust starting point and ending point
  3975.         xs+=dx_left;
  3976.         xe+=dx_right;
  3977.  
  3978.         } // end for
  3979.  
  3980.     } // end if no x clipping needed
  3981. else
  3982.    {
  3983.    // clip x axis with slower version
  3984.  
  3985.    // draw the triangle
  3986.  
  3987.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  3988.        {
  3989.        // do x clip
  3990.        left  = (int)xs;
  3991.        right = (int)xe;
  3992.  
  3993.        // adjust starting point and ending point
  3994.        xs+=dx_left;
  3995.        xe+=dx_right;
  3996.  
  3997.        // clip line
  3998.        if (left < min_clip_x)
  3999.           {
  4000.           left = min_clip_x;
  4001.  
  4002.           if (right < min_clip_x)
  4003.              continue;
  4004.           }
  4005.  
  4006.        if (right > max_clip_x)
  4007.           {
  4008.           right = max_clip_x;
  4009.  
  4010.           if (left > max_clip_x)
  4011.              continue;
  4012.           }
  4013.  
  4014.        memset((UCHAR  *)dest_addr+(unsigned int)left,
  4015.               color,(unsigned int)(right-left+1));
  4016.  
  4017.        } // end for
  4018.  
  4019.    } // end else x clipping needed
  4020.  
  4021. } // end Draw_Bottom_Tri
  4022.  
  4023. ///////////////////////////////////////////////////////////////////////////////
  4024.  
  4025. void Draw_Top_Tri16(int x1,int y1, 
  4026.                     int x2,int y2, 
  4027.                     int x3,int y3,
  4028.                     int color, 
  4029.                     UCHAR *_dest_buffer, int mempitch)
  4030. {
  4031. // this function draws a triangle that has a flat top
  4032.  
  4033. float dx_right,    // the dx/dy ratio of the right edge of line
  4034.       dx_left,     // the dx/dy ratio of the left edge of line
  4035.       xs,xe,       // the starting and ending points of the edges
  4036.       height;      // the height of the triangle
  4037.  
  4038. int temp_x,        // used during sorting as temps
  4039.     temp_y,
  4040.     right,         // used by clipping
  4041.     left;
  4042.  
  4043. // cast dest buffer to ushort
  4044. USHORT *dest_buffer = (USHORT *)_dest_buffer;
  4045.  
  4046. // destination address of next scanline
  4047. USHORT  *dest_addr = NULL;
  4048.  
  4049. // recompute mempitch in 16-bit words
  4050. mempitch = (mempitch >> 1);
  4051.  
  4052. // test order of x1 and x2
  4053. if (x2 < x1)
  4054.    {
  4055.    temp_x = x2;
  4056.    x2     = x1;
  4057.    x1     = temp_x;
  4058.    } // end if swap
  4059.  
  4060. // compute delta's
  4061. height = y3-y1;
  4062.  
  4063. dx_left  = (x3-x1)/height;
  4064. dx_right = (x3-x2)/height;
  4065.  
  4066. // set starting points
  4067. xs = (float)x1;
  4068. xe = (float)x2+(float)0.5;
  4069.  
  4070. // perform y clipping
  4071. if (y1 < min_clip_y)
  4072.    {
  4073.    // compute new xs and ys
  4074.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  4075.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  4076.  
  4077.    // reset y1
  4078.    y1=min_clip_y;
  4079.  
  4080.    } // end if top is off screen
  4081.  
  4082. if (y3>max_clip_y)
  4083.    y3=max_clip_y;
  4084.  
  4085. // compute starting address in video memory
  4086. dest_addr = dest_buffer+y1*mempitch;
  4087.  
  4088. // test if x clipping is needed
  4089. if (x1>=min_clip_x && x1<=max_clip_x &&
  4090.     x2>=min_clip_x && x2<=max_clip_x &&
  4091.     x3>=min_clip_x && x3<=max_clip_x)
  4092.     {
  4093.     // draw the triangle
  4094.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4095.         {
  4096.         // draw the line
  4097.         Mem_Set_WORD(dest_addr+(unsigned int)xs,color,(unsigned int)(xe-xs+1));
  4098.  
  4099.         // adjust starting point and ending point
  4100.         xs+=dx_left;
  4101.         xe+=dx_right;
  4102.  
  4103.         } // end for
  4104.  
  4105.     } // end if no x clipping needed
  4106. else
  4107.    {
  4108.    // clip x axis with slower version
  4109.  
  4110.    // draw the triangle
  4111.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4112.        {
  4113.        // do x clip
  4114.        left  = (int)xs;
  4115.        right = (int)xe;
  4116.  
  4117.        // adjust starting point and ending point
  4118.        xs+=dx_left;
  4119.        xe+=dx_right;
  4120.  
  4121.        // clip line
  4122.        if (left < min_clip_x)
  4123.           {
  4124.           left = min_clip_x;
  4125.  
  4126.           if (right < min_clip_x)
  4127.              continue;
  4128.           }
  4129.  
  4130.        if (right > max_clip_x)
  4131.           {
  4132.           right = max_clip_x;
  4133.  
  4134.           if (left > max_clip_x)
  4135.              continue;
  4136.           }
  4137.  
  4138.         // draw the line
  4139.         Mem_Set_WORD(dest_addr+(unsigned int)left,color,(unsigned int)(right-left+1));
  4140.  
  4141.        } // end for
  4142.  
  4143.    } // end else x clipping needed
  4144.  
  4145. } // end Draw_Top_Tri16
  4146.  
  4147. /////////////////////////////////////////////////////////////////////////////
  4148.  
  4149. void Draw_Bottom_Tri16(int x1,int y1, 
  4150.                        int x2,int y2, 
  4151.                        int x3,int y3,
  4152.                        int color,
  4153.                        UCHAR *_dest_buffer, int mempitch)
  4154. {
  4155. // this function draws a triangle that has a flat bottom
  4156.  
  4157. float dx_right,    // the dx/dy ratio of the right edge of line
  4158.       dx_left,     // the dx/dy ratio of the left edge of line
  4159.       xs,xe,       // the starting and ending points of the edges
  4160.       height;      // the height of the triangle
  4161.  
  4162. int temp_x,        // used during sorting as temps
  4163.     temp_y,
  4164.     right,         // used by clipping
  4165.     left;
  4166.  
  4167. // cast dest buffer to ushort
  4168. USHORT *dest_buffer = (USHORT *)_dest_buffer;
  4169.  
  4170. // destination address of next scanline
  4171. USHORT  *dest_addr = NULL;
  4172.  
  4173. // recompute mempitch in 16-bit words
  4174. mempitch = (mempitch >> 1);
  4175.  
  4176. // test order of x1 and x2
  4177. if (x3 < x2)
  4178.    {
  4179.    temp_x = x2;
  4180.    x2     = x3;
  4181.    x3     = temp_x;
  4182.    } // end if swap
  4183.  
  4184. // compute delta's
  4185. height = y3-y1;
  4186.  
  4187. dx_left  = (x2-x1)/height;
  4188. dx_right = (x3-x1)/height;
  4189.  
  4190. // set starting points
  4191. xs = (float)x1;
  4192. xe = (float)x1; // +(float)0.5;
  4193.  
  4194. // perform y clipping
  4195. if (y1<min_clip_y)
  4196.    {
  4197.    // compute new xs and ys
  4198.    xs = xs+dx_left*(float)(-y1+min_clip_y);
  4199.    xe = xe+dx_right*(float)(-y1+min_clip_y);
  4200.  
  4201.    // reset y1
  4202.    y1=min_clip_y;
  4203.  
  4204.    } // end if top is off screen
  4205.  
  4206. if (y3>max_clip_y)
  4207.    y3=max_clip_y;
  4208.  
  4209. // compute starting address in video memory
  4210. dest_addr = dest_buffer+y1*mempitch;
  4211.  
  4212. // test if x clipping is needed
  4213. if (x1>=min_clip_x && x1<=max_clip_x &&
  4214.     x2>=min_clip_x && x2<=max_clip_x &&
  4215.     x3>=min_clip_x && x3<=max_clip_x)
  4216.     {
  4217.     // draw the triangle
  4218.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4219.         {
  4220.         // draw the line
  4221.         Mem_Set_WORD(dest_addr+(unsigned int)xs,color,(unsigned int)(xe-xs+1));
  4222.  
  4223.         // adjust starting point and ending point
  4224.         xs+=dx_left;
  4225.         xe+=dx_right;
  4226.  
  4227.         } // end for
  4228.  
  4229.     } // end if no x clipping needed
  4230. else
  4231.    {
  4232.    // clip x axis with slower version
  4233.  
  4234.    // draw the triangle
  4235.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4236.        {
  4237.        // do x clip
  4238.        left  = (int)xs;
  4239.        right = (int)xe;
  4240.  
  4241.        // adjust starting point and ending point
  4242.        xs+=dx_left;
  4243.        xe+=dx_right;
  4244.  
  4245.        // clip line
  4246.        if (left < min_clip_x)
  4247.           {
  4248.           left = min_clip_x;
  4249.  
  4250.           if (right < min_clip_x)
  4251.              continue;
  4252.           }
  4253.  
  4254.        if (right > max_clip_x)
  4255.           {
  4256.           right = max_clip_x;
  4257.  
  4258.           if (left > max_clip_x)
  4259.              continue;
  4260.           }
  4261.        // draw the line
  4262.        Mem_Set_WORD(dest_addr+(unsigned int)left,color,(unsigned int)(right-left+1));
  4263.  
  4264.        } // end for
  4265.  
  4266.    } // end else x clipping needed
  4267.  
  4268. } // end Draw_Bottom_Tri16
  4269.  
  4270. ///////////////////////////////////////////////////////////////////////////////
  4271.  
  4272. void Draw_TriangleFP_2D(int x1,int y1,
  4273.                         int x2,int y2,
  4274.                         int x3,int y3,
  4275.                         int color,
  4276.                            UCHAR *dest_buffer, int mempitch)
  4277. {
  4278. // this function draws a triangle on the destination buffer using fixed point
  4279. // it decomposes all triangles into a pair of flat top, flat bottom
  4280.  
  4281. int temp_x, // used for sorting
  4282.     temp_y,
  4283.     new_x;
  4284.  
  4285. // test for h lines and v lines
  4286. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  4287.    return;
  4288.  
  4289. // sort p1,p2,p3 in ascending y order
  4290. if (y2<y1)
  4291.    {
  4292.    temp_x = x2;
  4293.    temp_y = y2;
  4294.    x2     = x1;
  4295.    y2     = y1;
  4296.    x1     = temp_x;
  4297.    y1     = temp_y;
  4298.    } // end if
  4299.  
  4300. // now we know that p1 and p2 are in order
  4301. if (y3<y1)
  4302.    {
  4303.    temp_x = x3;
  4304.    temp_y = y3;
  4305.    x3     = x1;
  4306.    y3     = y1;
  4307.    x1     = temp_x;
  4308.    y1     = temp_y;
  4309.    } // end if
  4310.  
  4311. // finally test y3 against y2
  4312. if (y3<y2)
  4313.    {
  4314.    temp_x = x3;
  4315.    temp_y = y3;
  4316.    x3     = x2;
  4317.    y3     = y2;
  4318.    x2     = temp_x;
  4319.    y2     = temp_y;
  4320.  
  4321.    } // end if
  4322.  
  4323. // do trivial rejection tests for clipping
  4324. if ( y3<min_clip_y || y1>max_clip_y ||
  4325.     (x1<min_clip_x && x2<min_clip_x && x3<min_clip_x) ||
  4326.     (x1>max_clip_x && x2>max_clip_x && x3>max_clip_x) )
  4327.    return;
  4328.  
  4329. // test if top of triangle is flat
  4330. if (y1==y2)
  4331.    {
  4332.    Draw_Top_TriFP(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  4333.    } // end if
  4334. else
  4335. if (y2==y3)
  4336.    {
  4337.    Draw_Bottom_TriFP(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  4338.    } // end if bottom is flat
  4339. else
  4340.    {
  4341.    // general triangle that's needs to be broken up along long edge
  4342.    new_x = x1 + (int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  4343.  
  4344.    // draw each sub-triangle
  4345.    Draw_Bottom_TriFP(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  4346.    Draw_Top_TriFP(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  4347.  
  4348.    } // end else
  4349.  
  4350. } // end Draw_TriangleFP_2D
  4351.  
  4352. /////////////////////////////////////////////////////////////
  4353.  
  4354. void Draw_Triangle_2D(int x1,int y1,
  4355.                       int x2,int y2,
  4356.                       int x3,int y3,
  4357.                       int color,
  4358.                       UCHAR *dest_buffer, int mempitch)
  4359. {
  4360. // this function draws a triangle on the destination buffer
  4361. // it decomposes all triangles into a pair of flat top, flat bottom
  4362.  
  4363. int temp_x, // used for sorting
  4364.     temp_y,
  4365.     new_x;
  4366.  
  4367. // test for h lines and v lines
  4368. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  4369.    return;
  4370.  
  4371. // sort p1,p2,p3 in ascending y order
  4372. if (y2<y1)
  4373.    {
  4374.    temp_x = x2;
  4375.    temp_y = y2;
  4376.    x2     = x1;
  4377.    y2     = y1;
  4378.    x1     = temp_x;
  4379.    y1     = temp_y;
  4380.    } // end if
  4381.  
  4382. // now we know that p1 and p2 are in order
  4383. if (y3<y1)
  4384.    {
  4385.    temp_x = x3;
  4386.    temp_y = y3;
  4387.    x3     = x1;
  4388.    y3     = y1;
  4389.    x1     = temp_x;
  4390.    y1     = temp_y;
  4391.    } // end if
  4392.  
  4393. // finally test y3 against y2
  4394. if (y3<y2)
  4395.    {
  4396.    temp_x = x3;
  4397.    temp_y = y3;
  4398.    x3     = x2;
  4399.    y3     = y2;
  4400.    x2     = temp_x;
  4401.    y2     = temp_y;
  4402.  
  4403.    } // end if
  4404.  
  4405. // do trivial rejection tests for clipping
  4406. if ( y3<min_clip_y || y1>max_clip_y ||
  4407.     (x1<min_clip_x && x2<min_clip_x && x3<min_clip_x) ||
  4408.     (x1>max_clip_x && x2>max_clip_x && x3>max_clip_x) )
  4409.    return;
  4410.  
  4411. // test if top of triangle is flat
  4412. if (y1==y2)
  4413.    {
  4414.    Draw_Top_Tri(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  4415.    } // end if
  4416. else
  4417. if (y2==y3)
  4418.    {
  4419.    Draw_Bottom_Tri(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  4420.    } // end if bottom is flat
  4421. else
  4422.    {
  4423.    // general triangle that's needs to be broken up along long edge
  4424.    new_x = x1 + (int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  4425.  
  4426.    // draw each sub-triangle
  4427.    Draw_Bottom_Tri(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  4428.    Draw_Top_Tri(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  4429.  
  4430.    } // end else
  4431.  
  4432. } // end Draw_Triangle_2D
  4433.  
  4434. ///////////////////////////////////////////////////////////////////////////////
  4435.  
  4436. void Draw_Triangle_2D16(int x1,int y1,
  4437.                         int x2,int y2,
  4438.                         int x3,int y3,
  4439.                         int color,
  4440.                         UCHAR *dest_buffer, int mempitch)
  4441. {
  4442. // this function draws a triangle on the destination buffer
  4443. // it decomposes all triangles into a pair of flat top, flat bottom
  4444.  
  4445.  
  4446. int temp_x, // used for sorting
  4447.     temp_y,
  4448.     new_x;
  4449.  
  4450. // test for h lines and v lines
  4451. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  4452.    return;
  4453.  
  4454. // sort p1,p2,p3 in ascending y order
  4455. if (y2<y1)
  4456.    {
  4457.    temp_x = x2;
  4458.    temp_y = y2;
  4459.    x2     = x1;
  4460.    y2     = y1;
  4461.    x1     = temp_x;
  4462.    y1     = temp_y;
  4463.    } // end if
  4464.  
  4465. // now we know that p1 and p2 are in order
  4466. if (y3<y1)
  4467.    {
  4468.    temp_x = x3;
  4469.    temp_y = y3;
  4470.    x3     = x1;
  4471.    y3     = y1;
  4472.    x1     = temp_x;
  4473.    y1     = temp_y;
  4474.    } // end if
  4475.  
  4476. // finally test y3 against y2
  4477. if (y3<y2)
  4478.    {
  4479.    temp_x = x3;
  4480.    temp_y = y3;
  4481.    x3     = x2;
  4482.    y3     = y2;
  4483.    x2     = temp_x;
  4484.    y2     = temp_y;
  4485.  
  4486.    } // end if
  4487.  
  4488. // do trivial rejection tests for clipping
  4489. if ( y3<min_clip_y || y1>max_clip_y ||
  4490.     (x1<min_clip_x && x2<min_clip_x && x3<min_clip_x) ||
  4491.     (x1>max_clip_x && x2>max_clip_x && x3>max_clip_x) )
  4492.    return;
  4493.  
  4494. // test if top of triangle is flat
  4495. if (y1==y2)
  4496.    {
  4497.    Draw_Top_Tri16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  4498.    } // end if
  4499. else
  4500. if (y2==y3)
  4501.    {
  4502.    Draw_Bottom_Tri16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
  4503.    } // end if bottom is flat
  4504. else
  4505.    {
  4506.    // general triangle that's needs to be broken up along long edge
  4507.    new_x = x1 + (int)(0.5+(float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  4508.  
  4509.    // draw each sub-triangle
  4510.    Draw_Bottom_Tri16(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
  4511.    Draw_Top_Tri16(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
  4512.  
  4513.    } // end else
  4514.  
  4515. } // end Draw_Triangle_2D16
  4516.  
  4517. ////////////////////////////////////////////////////////////////////////////////
  4518.  
  4519. inline void Draw_QuadFP_2D(int x0,int y0,
  4520.                     int x1,int y1,
  4521.                     int x2,int y2,
  4522.                     int x3, int y3,
  4523.                     int color,
  4524.                     UCHAR *dest_buffer, int mempitch)
  4525. {
  4526. // this function draws a 2D quadrilateral
  4527.  
  4528. // simply call the triangle function 2x, let it do all the work
  4529. Draw_TriangleFP_2D(x0,y0,x1,y1,x3,y3,color,dest_buffer,mempitch);
  4530. Draw_TriangleFP_2D(x1,y1,x2,y2,x3,y3,color,dest_buffer,mempitch);
  4531.  
  4532. } // end Draw_QuadFP_2D
  4533.  
  4534. ////////////////////////////////////////////////////////////////////////////////
  4535.  
  4536. void Draw_Top_TriFP(int x1,int y1,
  4537.                     int x2,int y2, 
  4538.                     int x3,int y3,
  4539.                     int color, 
  4540.                     UCHAR *dest_buffer, int mempitch)
  4541. {
  4542. // this function draws a triangle that has a flat top using fixed point math
  4543.  
  4544. int dx_right,    // the dx/dy ratio of the right edge of line
  4545.     dx_left,     // the dx/dy ratio of the left edge of line
  4546.     xs,xe,       // the starting and ending points of the edges
  4547.     height;      // the height of the triangle
  4548.  
  4549. int temp_x,        // used during sorting as temps
  4550.     temp_y,
  4551.     right,         // used by clipping
  4552.     left;
  4553.  
  4554. UCHAR  *dest_addr;
  4555.  
  4556. // test for degenerate
  4557. if (y1==y3 || y2==y3)
  4558.     return;
  4559.  
  4560. // test order of x1 and x2
  4561. if (x2 < x1)
  4562.    {
  4563.    temp_x = x2;
  4564.    x2     = x1;
  4565.    x1     = temp_x;
  4566.    } // end if swap
  4567.  
  4568. // compute delta's
  4569. height = y3-y1;
  4570.  
  4571. dx_left  = ((x3-x1)<<FIXP16_SHIFT)/height;
  4572. dx_right = ((x3-x2)<<FIXP16_SHIFT)/height;
  4573.  
  4574. // set starting points
  4575. xs = (x1<<FIXP16_SHIFT);
  4576. xe = (x2<<FIXP16_SHIFT);
  4577.  
  4578. // perform y clipping
  4579. if (y1<min_clip_y)
  4580.    {
  4581.    // compute new xs and ys
  4582.    xs = xs+dx_left*(-y1+min_clip_y);
  4583.    xe = xe+dx_right*(-y1+min_clip_y);
  4584.  
  4585.    // reset y1
  4586.    y1=min_clip_y;
  4587.  
  4588.    } // end if top is off screen
  4589.  
  4590. if (y3>max_clip_y)
  4591.    y3=max_clip_y;
  4592.  
  4593. // compute starting address in video memory
  4594. dest_addr = dest_buffer+y1*mempitch;
  4595.  
  4596. // test if x clipping is needed
  4597. if (x1>=min_clip_x && x1<=max_clip_x &&
  4598.     x2>=min_clip_x && x2<=max_clip_x &&
  4599.     x3>=min_clip_x && x3<=max_clip_x)
  4600.     {
  4601.     // draw the triangle
  4602.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4603.         {
  4604.         memset((UCHAR *)dest_addr+((xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT),
  4605.                color, (((xe-xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT)+1));
  4606.  
  4607.         // adjust starting point and ending point
  4608.         xs+=dx_left;
  4609.         xe+=dx_right;
  4610.  
  4611.         } // end for
  4612.  
  4613.     } // end if no x clipping needed
  4614. else
  4615.    {
  4616.    // clip x axis with slower version
  4617.  
  4618.    // draw the triangle
  4619.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4620.        {
  4621.        // do x clip
  4622.        left  = ((xs+FIXP16_ROUND_UP)>>16);
  4623.        right = ((xe+FIXP16_ROUND_UP)>>16);
  4624.  
  4625.        // adjust starting point and ending point
  4626.        xs+=dx_left;
  4627.        xe+=dx_right;
  4628.  
  4629.        // clip line
  4630.        if (left < min_clip_x)
  4631.           {
  4632.           left = min_clip_x;
  4633.  
  4634.           if (right < min_clip_x)
  4635.              continue;
  4636.           }
  4637.  
  4638.        if (right > max_clip_x)
  4639.           {
  4640.           right = max_clip_x;
  4641.  
  4642.           if (left > max_clip_x)
  4643.              continue;
  4644.           }
  4645.  
  4646.        memset((UCHAR  *)dest_addr+(unsigned int)left,
  4647.               color,(unsigned int)(right-left+1));
  4648.  
  4649.        } // end for
  4650.  
  4651.    } // end else x clipping needed
  4652.  
  4653. } // end Draw_Top_TriFP
  4654.  
  4655. /////////////////////////////////////////////////////////////////////////////
  4656.  
  4657. void Draw_Bottom_TriFP(int x1,int y1, 
  4658.                        int x2,int y2, 
  4659.                        int x3,int y3,
  4660.                        int color,
  4661.                        UCHAR *dest_buffer, int mempitch)
  4662. {
  4663.  
  4664. // this function draws a triangle that has a flat bottom using fixed point math
  4665.  
  4666. int dx_right,    // the dx/dy ratio of the right edge of line
  4667.     dx_left,     // the dx/dy ratio of the left edge of line
  4668.     xs,xe,       // the starting and ending points of the edges
  4669.     height;      // the height of the triangle
  4670.  
  4671. int temp_x,        // used during sorting as temps
  4672.     temp_y,
  4673.     right,         // used by clipping
  4674.     left;
  4675.  
  4676. UCHAR  *dest_addr;
  4677.  
  4678. if (y1==y2 || y1==y3)
  4679.     return;
  4680.  
  4681. // test order of x1 and x2
  4682. if (x3 < x2)
  4683.    {
  4684.    temp_x = x2;
  4685.    x2     = x3;
  4686.    x3     = temp_x;
  4687.  
  4688.    } // end if swap
  4689.  
  4690. // compute delta's
  4691. height = y3-y1;
  4692.  
  4693. dx_left  = ((x2-x1)<<FIXP16_SHIFT)/height;
  4694. dx_right = ((x3-x1)<<FIXP16_SHIFT)/height;
  4695.  
  4696. // set starting points
  4697. xs = (x1<<FIXP16_SHIFT);
  4698. xe = (x1<<FIXP16_SHIFT); 
  4699.  
  4700. // perform y clipping
  4701. if (y1<min_clip_y)
  4702.    {
  4703.    // compute new xs and ys
  4704.    xs = xs+dx_left*(-y1+min_clip_y);
  4705.    xe = xe+dx_right*(-y1+min_clip_y);
  4706.  
  4707.    // reset y1
  4708.    y1=min_clip_y;
  4709.  
  4710.    } // end if top is off screen
  4711.  
  4712. if (y3>max_clip_y)
  4713.    y3=max_clip_y;
  4714.  
  4715. // compute starting address in video memory
  4716. dest_addr = dest_buffer+y1*mempitch;
  4717.  
  4718. // test if x clipping is needed
  4719. if (x1>=min_clip_x && x1<=max_clip_x &&
  4720.     x2>=min_clip_x && x2<=max_clip_x &&
  4721.     x3>=min_clip_x && x3<=max_clip_x)
  4722.     {
  4723.     // draw the triangle
  4724.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4725.         {
  4726.         memset((UCHAR *)dest_addr+((xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT),
  4727.                 color, (((xe-xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT)+1));
  4728.  
  4729.         // adjust starting point and ending point
  4730.         xs+=dx_left;
  4731.         xe+=dx_right;
  4732.  
  4733.         } // end for
  4734.  
  4735.     } // end if no x clipping needed
  4736. else
  4737.    {
  4738.    // clip x axis with slower version
  4739.  
  4740.    // draw the triangle
  4741.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=mempitch)
  4742.        {
  4743.        // do x clip
  4744.        left  = ((xs+FIXP16_ROUND_UP)>>FIXP16_SHIFT);
  4745.        right = ((xe+FIXP16_ROUND_UP)>>FIXP16_SHIFT);
  4746.  
  4747.        // adjust starting point and ending point
  4748.        xs+=dx_left;
  4749.        xe+=dx_right;
  4750.  
  4751.        // clip line
  4752.        if (left < min_clip_x)
  4753.           {
  4754.           left = min_clip_x;
  4755.  
  4756.           if (right < min_clip_x)
  4757.              continue;
  4758.           }
  4759.  
  4760.        if (right > max_clip_x)
  4761.           {
  4762.           right = max_clip_x;
  4763.  
  4764.           if (left > max_clip_x)
  4765.              continue;
  4766.           }
  4767.  
  4768.        memset((UCHAR *)dest_addr+left,
  4769.               color, (right-left+1));
  4770.  
  4771.        } // end for
  4772.  
  4773.    } // end else x clipping needed
  4774.  
  4775. } // end Draw_Bottom_TriFP
  4776.  
  4777. ////////////////////////////////////////////////////////////////////////////
  4778.  
  4779. int Fast_Distance_2D(int x, int y)
  4780. {
  4781. // this function computes the distance from 0,0 to x,y with 3.5% error
  4782.  
  4783. // first compute the absolute value of x,y
  4784. x = abs(x);
  4785. y = abs(y);
  4786.  
  4787. // compute the minimum of x,y
  4788. int mn = MIN(x,y);
  4789.  
  4790. // return the distance
  4791. return(x+y-(mn>>1)-(mn>>2)+(mn>>4));
  4792.  
  4793. } // end Fast_Distance_2D
  4794.  
  4795. ///////////////////////////////////////////////////////////////////////////////
  4796.  
  4797. float Fast_Distance_3D(float fx, float fy, float fz)
  4798. {
  4799. // this function computes the distance from the origin to x,y,z
  4800.  
  4801. int temp;  // used for swaping
  4802. int x,y,z; // used for algorithm
  4803.  
  4804. // make sure values are all positive
  4805. x = fabs(fx) * 1024;
  4806. y = fabs(fy) * 1024;
  4807. z = fabs(fz) * 1024;
  4808.  
  4809. // sort values
  4810. if (y < x) SWAP(x,y,temp)
  4811.  
  4812. if (z < y) SWAP(y,z,temp)
  4813.  
  4814. if (y < x) SWAP(x,y,temp)
  4815.  
  4816. int dist = (z + 11*(y >> 5) + (x >> 2) );
  4817.  
  4818. // compute distance with 8% error
  4819. return((float)(dist >> 10));
  4820.  
  4821. } // end Fast_Distance_3D
  4822.  
  4823. ///////////////////////////////////////////////////////////////////////////////
  4824.  
  4825. int Find_Bounding_Box_Poly2D(POLYGON2D_PTR poly, 
  4826.                              float &min_x, float &max_x, 
  4827.                              float &min_y, float &max_y)
  4828. {
  4829. // this function finds the bounding box of a 2D polygon 
  4830. // and returns the values in the sent vars
  4831.  
  4832. // is this poly valid?
  4833. if (poly->num_verts == 0)
  4834.     return(0);
  4835.  
  4836. // initialize output vars (note they are pointers)
  4837. // also note that the algorithm assumes local coordinates
  4838. // that is, the poly verts are relative to 0,0
  4839. max_x = max_y = min_x = min_y = 0;
  4840.  
  4841. // process each vertex
  4842. for (int index=0; index < poly->num_verts; index++)
  4843.     {
  4844.     // update vars - run min/max seek
  4845.     if (poly->vlist[index].x > max_x)
  4846.        max_x = poly->vlist[index].x;
  4847.  
  4848.     if (poly->vlist[index].x < min_x)
  4849.        min_x = poly->vlist[index].x;
  4850.  
  4851.     if (poly->vlist[index].y > max_y)
  4852.        max_y = poly->vlist[index].y;
  4853.  
  4854.     if (poly->vlist[index].y < min_y)
  4855.        min_y = poly->vlist[index].y;
  4856.  
  4857. } // end for index
  4858.  
  4859. // return success
  4860. return(1);
  4861.  
  4862. } // end Find_Bounding_Box_Poly2D
  4863.  
  4864. ////////////////////////////////////////////////////////////////
  4865.  
  4866. void Draw_Filled_Polygon2D(POLYGON2D_PTR poly, UCHAR *vbuffer, int mempitch)
  4867. {
  4868. // this function draws a general n sided polygon 
  4869.  
  4870. int ydiff1, ydiff2,         // difference between starting x and ending x
  4871.     xdiff1, xdiff2,         // difference between starting y and ending y
  4872.     start,                  // starting offset of line between edges
  4873.     length,                 // distance from edge 1 to edge 2
  4874.     errorterm1, errorterm2, // error terms for edges 1 & 2
  4875.     offset1, offset2,       // offset of current pixel in edges 1 & 2
  4876.     count1, count2,         // increment count for edges 1 & 2
  4877.     xunit1, xunit2;         // unit to advance x offset for edges 1 & 2
  4878.  
  4879. // initialize count of number of edges drawn:
  4880. int edgecount = poly->num_verts-1;
  4881.  
  4882. // determine which vertex is at top of polygon:
  4883.  
  4884. int firstvert=0;         // start by assuming vertex 0 is at top
  4885.  
  4886. int min_y=poly->vlist[0].y; // find y coordinate of vertex 0
  4887.  
  4888. for (int index=1; index < poly->num_verts; index++) 
  4889.     {  
  4890.     // Search thru vertices
  4891.      if ((poly->vlist[index].y) < min_y) 
  4892.         {  
  4893.         // is another vertex higher?
  4894.         firstvert=index;                   
  4895.         min_y=poly->vlist[index].y;
  4896.         } // end if
  4897.  
  4898.     } // end for index
  4899.  
  4900. // finding starting and ending vertices of first two edges:
  4901. int startvert1=firstvert;      // get starting vertex of edge 1
  4902. int startvert2=firstvert;      // get starting vertex of edge 2
  4903. int xstart1=poly->vlist[startvert1].x+poly->x0;
  4904. int ystart1=poly->vlist[startvert1].y+poly->y0;
  4905. int xstart2=poly->vlist[startvert2].x+poly->x0;
  4906. int ystart2=poly->vlist[startvert2].y+poly->y0;
  4907. int endvert1=startvert1-1;           // get ending vertex of edge 1
  4908.  
  4909. if (endvert1 < 0) 
  4910.    endvert1=poly->num_verts-1;    // check for wrap
  4911.  
  4912. int xend1=poly->vlist[endvert1].x+poly->x0;      // get x & y coordinates
  4913. int yend1=poly->vlist[endvert1].y+poly->y0;      // of ending vertices
  4914. int endvert2=startvert2+1;           // get ending vertex of edge 2
  4915.  
  4916. if (endvert2==(poly->num_verts)) 
  4917.     endvert2=0;  // Check for wrap
  4918.  
  4919. int xend2=poly->vlist[endvert2].x+poly->x0;      // get x & y coordinates
  4920. int yend2=poly->vlist[endvert2].y+poly->y0;      // of ending vertices
  4921.  
  4922. // draw the polygon:
  4923.  
  4924. while (edgecount>0) 
  4925.       {    
  4926.       // continue drawing until all edges drawn
  4927.       offset1=mempitch*ystart1+xstart1;  // offset of edge 1
  4928.       offset2=mempitch*ystart2+xstart2;  // offset of edge 2
  4929.       
  4930.       // initialize error terms
  4931.       // for edges 1 & 2
  4932.       errorterm1=0;        
  4933.       errorterm2=0;           
  4934.  
  4935.       // get absolute value of
  4936.          if ((ydiff1=yend1-ystart1) < 0) 
  4937.          ydiff1=-ydiff1;
  4938.  
  4939.       // x & y lengths of edges
  4940.       if ((ydiff2=yend2-ystart2) < 0) 
  4941.          ydiff2=-ydiff2; 
  4942.  
  4943.         if ((xdiff1=xend1-xstart1) < 0) 
  4944.          {               
  4945.          // get value of length
  4946.          xunit1=-1;                    // calculate X increment
  4947.          xdiff1=-xdiff1;
  4948.          } // end if
  4949.       else 
  4950.          {
  4951.          xunit1=1;
  4952.          } // end else
  4953.  
  4954.          if ((xdiff2=xend2-xstart2) < 0) 
  4955.          {
  4956.          // Get value of length
  4957.            xunit2=-1;                   // calculate X increment
  4958.          xdiff2=-xdiff2;
  4959.          } // end else
  4960.       else 
  4961.          {
  4962.          xunit2=1;
  4963.          } // end else
  4964.  
  4965.       // choose which of four routines to use
  4966.       if (xdiff1 > ydiff1) 
  4967.          {    
  4968.          // if x length of edge 1 is greater than y length
  4969.          if (xdiff2 > ydiff2) 
  4970.             {  
  4971.             // if X length of edge 2 is greater than y length
  4972.  
  4973.             // increment edge 1 on X and edge 2 on X:
  4974.             count1=xdiff1;    // count for x increment on edge 1
  4975.             count2=xdiff2;    // count for x increment on edge 2
  4976.  
  4977.             while (count1 && count2) 
  4978.                   {  
  4979.                   // continue drawing until one edge is done
  4980.                   // calculate edge 1:
  4981.                     while ((errorterm1 < xdiff1) && (count1 > 0)) 
  4982.                         { 
  4983.                         // finished w/edge 1?
  4984.                         if (count1--) 
  4985.                            {     
  4986.                            // count down on edge 1
  4987.                            offset1+=xunit1;  // increment pixel offset
  4988.                            xstart1+=xunit1;
  4989.                            } // end if
  4990.  
  4991.                           errorterm1+=ydiff1; // increment error term
  4992.  
  4993.                          if (errorterm1 < xdiff1) 
  4994.                            {  // if not more than XDIFF
  4995.                            vbuffer[offset1]=(UCHAR)poly->color; // ...plot a pixel
  4996.                            } // end if
  4997.  
  4998.                          } // end while
  4999.                     
  5000.                   errorterm1-=xdiff1; // if time to increment X, restore error term
  5001.  
  5002.                   // calculate edge 2:
  5003.  
  5004.                   while ((errorterm2 < xdiff2) && (count2 > 0)) 
  5005.                         {  
  5006.                         // finished w/edge 2?
  5007.                         if (count2--) 
  5008.                            {     
  5009.                            // count down on edge 2
  5010.                            offset2+=xunit2;  // increment pixel offset
  5011.                            xstart2+=xunit2;
  5012.                            } // end if
  5013.  
  5014.                             errorterm2+=ydiff2; // increment error term
  5015.  
  5016.                           if (errorterm2 < xdiff2) 
  5017.                              {  // if not more than XDIFF
  5018.                              vbuffer[offset2]=(UCHAR)poly->color;  // ...plot a pixel
  5019.                              } // end if
  5020.  
  5021.                              } // end while
  5022.  
  5023.                     errorterm2-=xdiff2; // if time to increment X, restore error term
  5024.  
  5025.                     // draw line from edge 1 to edge 2:
  5026.  
  5027.                     length=offset2-offset1; // determine length of horizontal line
  5028.  
  5029.                     if (length < 0) 
  5030.                        { // if negative...
  5031.                        length=-length;       // make it positive
  5032.                        start=offset2;        // and set START to edge 2
  5033.                          } // end if
  5034.                     else 
  5035.                        start=offset1;     // else set START to edge 1
  5036.              
  5037.               for (int index=start; index < start+length+1; index++)
  5038.                   {  // From edge to edge...
  5039.                   vbuffer[index]=(UCHAR)poly->color;         // ...draw the line
  5040.                   } // end for index
  5041.  
  5042.                 offset1+=mempitch;           // advance edge 1 offset to next line
  5043.                   ystart1++;
  5044.                 offset2+=mempitch;           // advance edge 2 offset to next line
  5045.                 ystart2++;
  5046.  
  5047.                  } // end if
  5048.  
  5049.             } // end if
  5050.             else 
  5051.             {
  5052.                 // increment edge 1 on X and edge 2 on Y:
  5053.             count1=xdiff1;    // count for X increment on edge 1
  5054.             count2=ydiff2;    // count for Y increment on edge 2
  5055.             
  5056.             while (count1 && count2) 
  5057.                   {  // continue drawing until one edge is done
  5058.                         // calculate edge 1:
  5059.                    while ((errorterm1 < xdiff1) && (count1 > 0)) 
  5060.                         { // finished w/edge 1?
  5061.                            if (count1--) 
  5062.                            {
  5063.                            // count down on edge 1
  5064.                            offset1+=xunit1;  // increment pixel offset
  5065.                            xstart1+=xunit1;
  5066.                            } // end if
  5067.  
  5068.                         errorterm1+=ydiff1; // increment error term
  5069.  
  5070.                         if (errorterm1 < xdiff1) 
  5071.                            {  // If not more than XDIFF
  5072.                            vbuffer[offset1]=(UCHAR)poly->color; // ...plot a pixel
  5073.                            } // end if
  5074.  
  5075.                          } // end while
  5076.  
  5077.                     errorterm1-=xdiff1; // If time to increment X, restore error term
  5078.  
  5079.                       // calculate edge 2:
  5080.                     errorterm2+=xdiff2; // increment error term
  5081.                     
  5082.                     if (errorterm2 >= ydiff2)  
  5083.                        { // if time to increment Y...
  5084.                        errorterm2-=ydiff2;        // ...restore error term
  5085.                        offset2+=xunit2;           // ...and advance offset to next pixel
  5086.                        xstart2+=xunit2;
  5087.                         } // end if
  5088.  
  5089.                     count2--;
  5090.  
  5091.                     // draw line from edge 1 to edge 2:
  5092.  
  5093.                     length=offset2-offset1; // determine length of horizontal line
  5094.  
  5095.                     if (length < 0)  
  5096.                        { // if negative...
  5097.                        length=-length;       // ...make it positive
  5098.                        start=offset2;        // and set START to edge 2
  5099.                        } // end if
  5100.                     else 
  5101.                        start=offset1;        // else set START to edge 1
  5102.  
  5103.                     for (int index=start; index < start+length+1; index++)  // from edge to edge
  5104.                         {
  5105.                         vbuffer[index]=(UCHAR)poly->color;         // ...draw the line
  5106.                         } // end for index
  5107.  
  5108.                     offset1+=mempitch;           // advance edge 1 offset to next line
  5109.                     ystart1++;
  5110.                     offset2+=mempitch;           // advance edge 2 offset to next line
  5111.                     ystart2++;
  5112.  
  5113.                 } // end while
  5114.             } // end if
  5115.         } // end if
  5116.         else 
  5117.             {
  5118.             if (xdiff2 > ydiff2) 
  5119.                {
  5120.                   // increment edge 1 on Y and edge 2 on X:
  5121.  
  5122.                count1=ydiff1;  // count for Y increment on edge 1
  5123.                count2=xdiff2;  // count for X increment on edge 2
  5124.  
  5125.                while(count1 && count2) 
  5126.                     {  // continue drawing until one edge is done
  5127.                       // calculate edge 1:
  5128.  
  5129.                     errorterm1+=xdiff1; // Increment error term
  5130.  
  5131.                     if (errorterm1 >= ydiff1)  
  5132.                        {  // if time to increment Y...
  5133.                        errorterm1-=ydiff1;         // ...restore error term
  5134.                        offset1+=xunit1;            // ...and advance offset to next pixel
  5135.                        xstart1+=xunit1;
  5136.                        } // end if
  5137.  
  5138.                       count1--;
  5139.  
  5140.                     // Calculate edge 2:
  5141.  
  5142.                     while ((errorterm2 < xdiff2) && (count2 > 0)) 
  5143.                           { // finished w/edge 1?
  5144.                           if (count2--) 
  5145.                              { // count down on edge 2
  5146.                              offset2+=xunit2;  // increment pixel offset
  5147.                              xstart2+=xunit2;
  5148.                              } // end if
  5149.  
  5150.                           errorterm2+=ydiff2; // increment error term
  5151.  
  5152.                           if (errorterm2 < xdiff2) 
  5153.                              {  // if not more than XDIFF
  5154.                              vbuffer[offset2]=(UCHAR)poly->color; // ...plot a pixel
  5155.                              } // end if
  5156.                            } // end while
  5157.  
  5158.                     errorterm2-=xdiff2;  // if time to increment X, restore error term
  5159.  
  5160.                    // draw line from edge 1 to edge 2:
  5161.  
  5162.                     length=offset2-offset1; // determine length of horizontal line
  5163.  
  5164.                     if (length < 0) 
  5165.                        {    // if negative...
  5166.                        length=-length;  // ...make it positive
  5167.                        start=offset2;   // and set START to edge 2
  5168.                        } // end if
  5169.                     else 
  5170.                        start=offset1;  // else set START to edge 1
  5171.  
  5172.                       for (int index=start; index < start+length+1; index++) // from edge to edge...
  5173.                         {
  5174.                         vbuffer[index]=(UCHAR)poly->color;      // ...draw the line
  5175.                         } // end for index
  5176.  
  5177.                     offset1+=mempitch;         // advance edge 1 offset to next line
  5178.                     ystart1++;
  5179.                     offset2+=mempitch;         // advance edge 2 offset to next line
  5180.                     ystart2++;
  5181.  
  5182.                 } // end if
  5183.             } // end if
  5184.             else 
  5185.                {
  5186.                // increment edge 1 on Y and edge 2 on Y:
  5187.                  count1=ydiff1;  // count for Y increment on edge 1
  5188.                count2=ydiff2;  // count for Y increment on edge 2
  5189.  
  5190.                while(count1 && count2) 
  5191.                     {  
  5192.                     // continue drawing until one edge is done
  5193.                       // calculate edge 1:
  5194.                     errorterm1+=xdiff1;  // increment error term
  5195.  
  5196.                     if (errorterm1 >= ydiff1)  
  5197.                        {                           // if time to increment Y
  5198.                        errorterm1-=ydiff1;         // ...restore error term
  5199.                        offset1+=xunit1;            // ...and advance offset to next pixel
  5200.                        xstart1+=xunit1;
  5201.                        } // end if
  5202.              
  5203.                     count1--;
  5204.  
  5205.                        // calculate edge 2:
  5206.                     errorterm2+=xdiff2;            // increment error term
  5207.  
  5208.                     if (errorterm2 >= ydiff2)  
  5209.                        {                           // if time to increment Y
  5210.                        errorterm2-=ydiff2;         // ...restore error term
  5211.                        offset2+=xunit2;            // ...and advance offset to next pixel
  5212.                        xstart2+=xunit2;
  5213.                        } // end if
  5214.  
  5215.                        --count2;
  5216.  
  5217.                     // draw line from edge 1 to edge 2:
  5218.  
  5219.                     length=offset2-offset1;  // determine length of horizontal line
  5220.  
  5221.                     if (length < 0) 
  5222.                        {          
  5223.                        // if negative...
  5224.                        length=-length;        // ...make it positive
  5225.                        start=offset2;         // and set START to edge 2
  5226.                        } // end if
  5227.                     else 
  5228.                        start=offset1;         // else set START to edge 1
  5229.  
  5230.                     for (int index=start; index < start+length+1; index++)   
  5231.                         { // from edge to edge
  5232.                         vbuffer[index]=(UCHAR)poly->color;   // ...draw the linee
  5233.                         } // end for index
  5234.  
  5235.                     offset1+=mempitch;            // advance edge 1 offset to next line
  5236.                     ystart1++;
  5237.                     offset2+=mempitch;            // advance edge 2 offset to next line
  5238.                     ystart2++;
  5239.  
  5240.                 } // end while
  5241.  
  5242.             } // end else
  5243.  
  5244.         } // end if
  5245.  
  5246.         // another edge (at least) is complete. Start next edge, if any.
  5247.         if (!count1) 
  5248.            {                      // if edge 1 is complete...
  5249.            --edgecount;           // decrement the edge count
  5250.            startvert1=endvert1;   // make ending vertex into start vertex
  5251.            --endvert1;            // and get new ending vertex
  5252.         
  5253.            if (endvert1 < 0) 
  5254.               endvert1=poly->num_verts-1; // check for wrap
  5255.  
  5256.             xend1=poly->vlist[endvert1].x+poly->x0;  // get x & y of new end vertex
  5257.             yend1=poly->vlist[endvert1].y+poly->y0;
  5258.             } // end if
  5259.  
  5260.         if (!count2) 
  5261.            {                     // if edge 2 is complete...
  5262.            --edgecount;          // decrement the edge count
  5263.            startvert2=endvert2;  // make ending vertex into start vertex
  5264.            endvert2++;           // and get new ending vertex
  5265.         
  5266.            if (endvert2==(poly->num_verts)) 
  5267.               endvert2=0;                // check for wrap
  5268.  
  5269.             xend2=poly->vlist[endvert2].x+poly->x0;  // get x & y of new end vertex
  5270.             yend2=poly->vlist[endvert2].y+poly->y0;
  5271.  
  5272.            } // end if
  5273.  
  5274.     } // end while
  5275.  
  5276. } // end Draw_Filled_Polygon2D
  5277.  
  5278. ///////////////////////////////////////////////////////////////
  5279.  
  5280. void Draw_Filled_Polygon2D16(POLYGON2D_PTR poly, UCHAR *_vbuffer, int mempitch)
  5281. {
  5282. // this function draws a general n sided polygon 
  5283.  
  5284. int ydiff1, ydiff2,         // difference between starting x and ending x
  5285.     xdiff1, xdiff2,         // difference between starting y and ending y
  5286.     start,                  // starting offset of line between edges
  5287.     length,                 // distance from edge 1 to edge 2
  5288.     errorterm1, errorterm2, // error terms for edges 1 & 2
  5289.     offset1, offset2,       // offset of current pixel in edges 1 & 2
  5290.     count1, count2,         // increment count for edges 1 & 2
  5291.     xunit1, xunit2;         // unit to advance x offset for edges 1 & 2
  5292.  
  5293.  
  5294. // recast vbuffer into short version since this is a 16 bit mode
  5295. USHORT *vbuffer = (USHORT *)_vbuffer;
  5296.  
  5297. // convert mempitch into WORD or 16bit stride
  5298. mempitch = (mempitch >> 1);
  5299.  
  5300. // initialize count of number of edges drawn:
  5301. int edgecount = poly->num_verts-1;
  5302.  
  5303. // determine which vertex is at top of polygon:
  5304.  
  5305. int firstvert=0;         // start by assuming vertex 0 is at top
  5306.  
  5307. int min_y=poly->vlist[0].y; // find y coordinate of vertex 0
  5308.  
  5309. for (int index=1; index < poly->num_verts; index++) 
  5310.     {  
  5311.     // Search thru vertices
  5312.      if ((poly->vlist[index].y) < min_y) 
  5313.         {  
  5314.         // is another vertex higher?
  5315.         firstvert=index;                   
  5316.         min_y=poly->vlist[index].y;
  5317.         } // end if
  5318.  
  5319.     } // end for index
  5320.  
  5321. // finding starting and ending vertices of first two edges:
  5322. int startvert1=firstvert;      // get starting vertex of edge 1
  5323. int startvert2=firstvert;      // get starting vertex of edge 2
  5324. int xstart1=poly->vlist[startvert1].x+poly->x0;
  5325. int ystart1=poly->vlist[startvert1].y+poly->y0;
  5326. int xstart2=poly->vlist[startvert2].x+poly->x0;
  5327. int ystart2=poly->vlist[startvert2].y+poly->y0;
  5328. int endvert1=startvert1-1;           // get ending vertex of edge 1
  5329.  
  5330. if (endvert1 < 0) 
  5331.    endvert1=poly->num_verts-1;    // check for wrap
  5332.  
  5333. int xend1=poly->vlist[endvert1].x+poly->x0;      // get x & y coordinates
  5334. int yend1=poly->vlist[endvert1].y+poly->y0;      // of ending vertices
  5335. int endvert2=startvert2+1;           // get ending vertex of edge 2
  5336.  
  5337. if (endvert2==(poly->num_verts)) 
  5338.     endvert2=0;  // Check for wrap
  5339.  
  5340. int xend2=poly->vlist[endvert2].x+poly->x0;      // get x & y coordinates
  5341. int yend2=poly->vlist[endvert2].y+poly->y0;      // of ending vertices
  5342.  
  5343. // draw the polygon:
  5344.  
  5345. while (edgecount>0) 
  5346.       {    
  5347.       // continue drawing until all edges drawn
  5348.       offset1=mempitch*ystart1+xstart1;  // offset of edge 1
  5349.       offset2=mempitch*ystart2+xstart2;  // offset of edge 2
  5350.       
  5351.       // initialize error terms
  5352.       // for edges 1 & 2
  5353.       errorterm1=0;        
  5354.       errorterm2=0;           
  5355.  
  5356.       // get absolute value of
  5357.          if ((ydiff1=yend1-ystart1) < 0) 
  5358.          ydiff1=-ydiff1;
  5359.  
  5360.       // x & y lengths of edges
  5361.       if ((ydiff2=yend2-ystart2) < 0) 
  5362.          ydiff2=-ydiff2; 
  5363.  
  5364.         if ((xdiff1=xend1-xstart1) < 0) 
  5365.          {               
  5366.          // get value of length
  5367.          xunit1=-1;                    // calculate X increment
  5368.          xdiff1=-xdiff1;
  5369.          } // end if
  5370.       else 
  5371.          {
  5372.          xunit1=1;
  5373.          } // end else
  5374.  
  5375.          if ((xdiff2=xend2-xstart2) < 0) 
  5376.          {
  5377.          // Get value of length
  5378.            xunit2=-1;                   // calculate X increment
  5379.          xdiff2=-xdiff2;
  5380.          } // end else
  5381.       else 
  5382.          {
  5383.          xunit2=1;
  5384.          } // end else
  5385.  
  5386.       // choose which of four routines to use
  5387.       if (xdiff1 > ydiff1) 
  5388.          {    
  5389.          // if x length of edge 1 is greater than y length
  5390.          if (xdiff2 > ydiff2) 
  5391.             {  
  5392.             // if X length of edge 2 is greater than y length
  5393.  
  5394.             // increment edge 1 on X and edge 2 on X:
  5395.             count1=xdiff1;    // count for x increment on edge 1
  5396.             count2=xdiff2;    // count for x increment on edge 2
  5397.  
  5398.             while (count1 && count2) 
  5399.                   {  
  5400.                   // continue drawing until one edge is done
  5401.                   // calculate edge 1:
  5402.                     while ((errorterm1 < xdiff1) && (count1 > 0)) 
  5403.                         { 
  5404.                         // finished w/edge 1?
  5405.                         if (count1--) 
  5406.                            {     
  5407.                            // count down on edge 1
  5408.                            offset1+=xunit1;  // increment pixel offset
  5409.                            xstart1+=xunit1;
  5410.                            } // end if
  5411.  
  5412.                           errorterm1+=ydiff1; // increment error term
  5413.  
  5414.                          if (errorterm1 < xdiff1) 
  5415.                            {  // if not more than XDIFF
  5416.                            vbuffer[offset1]=(USHORT)poly->color; // ...plot a pixel
  5417.                            } // end if
  5418.  
  5419.                          } // end while
  5420.                     
  5421.                   errorterm1-=xdiff1; // if time to increment X, restore error term
  5422.  
  5423.                   // calculate edge 2:
  5424.  
  5425.                   while ((errorterm2 < xdiff2) && (count2 > 0)) 
  5426.                         {  
  5427.                         // finished w/edge 2?
  5428.                         if (count2--) 
  5429.                            {     
  5430.                            // count down on edge 2
  5431.                            offset2+=xunit2;  // increment pixel offset
  5432.                            xstart2+=xunit2;
  5433.                            } // end if
  5434.  
  5435.                             errorterm2+=ydiff2; // increment error term
  5436.  
  5437.                           if (errorterm2 < xdiff2) 
  5438.                              {  // if not more than XDIFF
  5439.                              vbuffer[offset2]=(USHORT)poly->color;  // ...plot a pixel
  5440.                              } // end if
  5441.  
  5442.                              } // end while
  5443.  
  5444.                     errorterm2-=xdiff2; // if time to increment X, restore error term
  5445.  
  5446.                     // draw line from edge 1 to edge 2:
  5447.  
  5448.                     length=offset2-offset1; // determine length of horizontal line
  5449.  
  5450.                     if (length < 0) 
  5451.                        { // if negative...
  5452.                        length=-length;       // make it positive
  5453.                        start=offset2;        // and set START to edge 2
  5454.                          } // end if
  5455.                     else 
  5456.                        start=offset1;     // else set START to edge 1
  5457.              
  5458.               for (int index=start; index < start+length+1; index++)
  5459.                   {  // From edge to edge...
  5460.                   vbuffer[index]=(USHORT)poly->color;         // ...draw the line
  5461.                   } // end for index
  5462.  
  5463.                 offset1+=mempitch;           // advance edge 1 offset to next line
  5464.                   ystart1++;
  5465.                 offset2+=mempitch;           // advance edge 2 offset to next line
  5466.                 ystart2++;
  5467.  
  5468.                  } // end if
  5469.  
  5470.             } // end if
  5471.             else 
  5472.             {
  5473.                 // increment edge 1 on X and edge 2 on Y:
  5474.             count1=xdiff1;    // count for X increment on edge 1
  5475.             count2=ydiff2;    // count for Y increment on edge 2
  5476.             
  5477.             while (count1 && count2) 
  5478.                   {  // continue drawing until one edge is done
  5479.                         // calculate edge 1:
  5480.                    while ((errorterm1 < xdiff1) && (count1 > 0)) 
  5481.                         { // finished w/edge 1?
  5482.                            if (count1--) 
  5483.                            {
  5484.                            // count down on edge 1
  5485.                            offset1+=xunit1;  // increment pixel offset
  5486.                            xstart1+=xunit1;
  5487.                            } // end if
  5488.  
  5489.                         errorterm1+=ydiff1; // increment error term
  5490.  
  5491.                         if (errorterm1 < xdiff1) 
  5492.                            {  // If not more than XDIFF
  5493.                            vbuffer[offset1]=(USHORT)poly->color; // ...plot a pixel
  5494.                            } // end if
  5495.  
  5496.                          } // end while
  5497.  
  5498.                     errorterm1-=xdiff1; // If time to increment X, restore error term
  5499.  
  5500.                       // calculate edge 2:
  5501.                     errorterm2+=xdiff2; // increment error term
  5502.                     
  5503.                     if (errorterm2 >= ydiff2)  
  5504.                        { // if time to increment Y...
  5505.                        errorterm2-=ydiff2;        // ...restore error term
  5506.                        offset2+=xunit2;           // ...and advance offset to next pixel
  5507.                        xstart2+=xunit2;
  5508.                         } // end if
  5509.  
  5510.                     count2--;
  5511.  
  5512.                     // draw line from edge 1 to edge 2:
  5513.  
  5514.                     length=offset2-offset1; // determine length of horizontal line
  5515.  
  5516.                     if (length < 0)  
  5517.                        { // if negative...
  5518.                        length=-length;       // ...make it positive
  5519.                        start=offset2;        // and set START to edge 2
  5520.                        } // end if
  5521.                     else 
  5522.                        start=offset1;        // else set START to edge 1
  5523.  
  5524.                     for (int index=start; index < start+length+1; index++)  // from edge to edge
  5525.                         {
  5526.                         vbuffer[index]=(USHORT)poly->color;         // ...draw the line
  5527.                         } // end for index
  5528.  
  5529.                     offset1+=mempitch;           // advance edge 1 offset to next line
  5530.                     ystart1++;
  5531.                     offset2+=mempitch;           // advance edge 2 offset to next line
  5532.                     ystart2++;
  5533.  
  5534.                 } // end while
  5535.             } // end if
  5536.         } // end if
  5537.         else 
  5538.             {
  5539.             if (xdiff2 > ydiff2) 
  5540.                {
  5541.                   // increment edge 1 on Y and edge 2 on X:
  5542.  
  5543.                count1=ydiff1;  // count for Y increment on edge 1
  5544.                count2=xdiff2;  // count for X increment on edge 2
  5545.  
  5546.                while(count1 && count2) 
  5547.                     {  // continue drawing until one edge is done
  5548.                       // calculate edge 1:
  5549.  
  5550.                     errorterm1+=xdiff1; // Increment error term
  5551.  
  5552.                     if (errorterm1 >= ydiff1)  
  5553.                        {  // if time to increment Y...
  5554.                        errorterm1-=ydiff1;         // ...restore error term
  5555.                        offset1+=xunit1;            // ...and advance offset to next pixel
  5556.                        xstart1+=xunit1;
  5557.                        } // end if
  5558.  
  5559.                       count1--;
  5560.  
  5561.                     // Calculate edge 2:
  5562.  
  5563.                     while ((errorterm2 < xdiff2) && (count2 > 0)) 
  5564.                           { // finished w/edge 1?
  5565.                           if (count2--) 
  5566.                              { // count down on edge 2
  5567.                              offset2+=xunit2;  // increment pixel offset
  5568.                              xstart2+=xunit2;
  5569.                              } // end if
  5570.  
  5571.                           errorterm2+=ydiff2; // increment error term
  5572.  
  5573.                           if (errorterm2 < xdiff2) 
  5574.                              {  // if not more than XDIFF
  5575.                              vbuffer[offset2]=(USHORT)poly->color; // ...plot a pixel
  5576.                              } // end if
  5577.                            } // end while
  5578.  
  5579.                     errorterm2-=xdiff2;  // if time to increment X, restore error term
  5580.  
  5581.                    // draw line from edge 1 to edge 2:
  5582.  
  5583.                     length=offset2-offset1; // determine length of horizontal line
  5584.  
  5585.                     if (length < 0) 
  5586.                        {    // if negative...
  5587.                        length=-length;  // ...make it positive
  5588.                        start=offset2;   // and set START to edge 2
  5589.                        } // end if
  5590.                     else 
  5591.                        start=offset1;  // else set START to edge 1
  5592.  
  5593.                       for (int index=start; index < start+length+1; index++) // from edge to edge...
  5594.                         {
  5595.                         vbuffer[index]=(USHORT)poly->color;      // ...draw the line
  5596.                         } // end for index
  5597.  
  5598.                     offset1+=mempitch;         // advance edge 1 offset to next line
  5599.                     ystart1++;
  5600.                     offset2+=mempitch;         // advance edge 2 offset to next line
  5601.                     ystart2++;
  5602.  
  5603.                 } // end if
  5604.             } // end if
  5605.             else 
  5606.                {
  5607.                // increment edge 1 on Y and edge 2 on Y:
  5608.                  count1=ydiff1;  // count for Y increment on edge 1
  5609.                count2=ydiff2;  // count for Y increment on edge 2
  5610.  
  5611.                while(count1 && count2) 
  5612.                     {  
  5613.                     // continue drawing until one edge is done
  5614.                       // calculate edge 1:
  5615.                     errorterm1+=xdiff1;  // increment error term
  5616.  
  5617.                     if (errorterm1 >= ydiff1)  
  5618.                        {                           // if time to increment Y
  5619.                        errorterm1-=ydiff1;         // ...restore error term
  5620.                        offset1+=xunit1;            // ...and advance offset to next pixel
  5621.                        xstart1+=xunit1;
  5622.                        } // end if
  5623.              
  5624.                     count1--;
  5625.  
  5626.                        // calculate edge 2:
  5627.                     errorterm2+=xdiff2;            // increment error term
  5628.  
  5629.                     if (errorterm2 >= ydiff2)  
  5630.                        {                           // if time to increment Y
  5631.                        errorterm2-=ydiff2;         // ...restore error term
  5632.                        offset2+=xunit2;            // ...and advance offset to next pixel
  5633.                        xstart2+=xunit2;
  5634.                        } // end if
  5635.  
  5636.                        --count2;
  5637.  
  5638.                     // draw line from edge 1 to edge 2:
  5639.  
  5640.                     length=offset2-offset1;  // determine length of horizontal line
  5641.  
  5642.                     if (length < 0) 
  5643.                        {          
  5644.                        // if negative...
  5645.                        length=-length;        // ...make it positive
  5646.                        start=offset2;         // and set START to edge 2
  5647.                        } // end if
  5648.                     else 
  5649.                        start=offset1;         // else set START to edge 1
  5650.  
  5651.                     for (int index=start; index < start+length+1; index++)   
  5652.                         { // from edge to edge
  5653.                         vbuffer[index]=(USHORT)poly->color;   // ...draw the linee
  5654.                         } // end for index
  5655.  
  5656.                     offset1+=mempitch;            // advance edge 1 offset to next line
  5657.                     ystart1++;
  5658.                     offset2+=mempitch;            // advance edge 2 offset to next line
  5659.                     ystart2++;
  5660.  
  5661.                 } // end while
  5662.  
  5663.             } // end else
  5664.  
  5665.         } // end if
  5666.  
  5667.         // another edge (at least) is complete. Start next edge, if any.
  5668.         if (!count1) 
  5669.            {                      // if edge 1 is complete...
  5670.            --edgecount;           // decrement the edge count
  5671.            startvert1=endvert1;   // make ending vertex into start vertex
  5672.            --endvert1;            // and get new ending vertex
  5673.         
  5674.            if (endvert1 < 0) 
  5675.               endvert1=poly->num_verts-1; // check for wrap
  5676.  
  5677.             xend1=poly->vlist[endvert1].x+poly->x0;  // get x & y of new end vertex
  5678.             yend1=poly->vlist[endvert1].y+poly->y0;
  5679.             } // end if
  5680.  
  5681.         if (!count2) 
  5682.            {                     // if edge 2 is complete...
  5683.            --edgecount;          // decrement the edge count
  5684.            startvert2=endvert2;  // make ending vertex into start vertex
  5685.            endvert2++;           // and get new ending vertex
  5686.         
  5687.            if (endvert2==(poly->num_verts)) 
  5688.               endvert2=0;                // check for wrap
  5689.  
  5690.             xend2=poly->vlist[endvert2].x+poly->x0;  // get x & y of new end vertex
  5691.             yend2=poly->vlist[endvert2].y+poly->y0;
  5692.  
  5693.            } // end if
  5694.  
  5695.     } // end while
  5696.  
  5697. } // end Draw_Filled_Polygon2D16
  5698.  
  5699. ///////////////////////////////////////////////////////////////
  5700.  
  5701. void Build_Sin_Cos_Tables(void)
  5702. {
  5703.   
  5704. // create sin/cos lookup table
  5705.  
  5706. // generate the tables
  5707. for (int ang = 0; ang < 360; ang++)
  5708.     {
  5709.     // convert ang to radians
  5710.     float theta = (float)ang*PI/(float)180;
  5711.  
  5712.     // insert next entry into table
  5713.     cos_look[ang] = cos(theta);
  5714.     sin_look[ang] = sin(theta);
  5715.  
  5716.     } // end for ang
  5717.  
  5718. } // end Build_Sin_Cos_Tables
  5719.  
  5720. //////////////////////////////////////////////////////////////
  5721.  
  5722. int Translate_Polygon2D(POLYGON2D_PTR poly, int dx, int dy)
  5723. {
  5724. // this function translates the center of a polygon
  5725.  
  5726. // test for valid pointer
  5727. if (!poly)
  5728.    return(0);
  5729.  
  5730. // translate
  5731. poly->x0+=dx;
  5732. poly->y0+=dy;
  5733.  
  5734. // return success
  5735. return(1);
  5736.  
  5737. } // end Translate_Polygon2D
  5738.  
  5739. ///////////////////////////////////////////////////////////////
  5740.  
  5741. int Rotate_Polygon2D(POLYGON2D_PTR poly, int theta)
  5742. {
  5743. // this function rotates the local coordinates of the polygon
  5744.  
  5745. // test for valid pointer
  5746. if (!poly)
  5747.    return(0);
  5748.  
  5749. // test for negative rotation angle
  5750. if (theta < 0)
  5751.    theta+=360;
  5752.  
  5753. // loop and rotate each point, very crude, no lookup!!!
  5754. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  5755.     {
  5756.  
  5757.     // perform rotation
  5758.     float xr = (float)poly->vlist[curr_vert].x*cos_look[theta] - 
  5759.                     (float)poly->vlist[curr_vert].y*sin_look[theta];
  5760.  
  5761.     float yr = (float)poly->vlist[curr_vert].x*sin_look[theta] + 
  5762.                     (float)poly->vlist[curr_vert].y*cos_look[theta];
  5763.  
  5764.     // store result back
  5765.     poly->vlist[curr_vert].x = xr;
  5766.     poly->vlist[curr_vert].y = yr;
  5767.  
  5768.     } // end for curr_vert
  5769.  
  5770. // return success
  5771. return(1);
  5772.  
  5773. } // end Rotate_Polygon2D
  5774.  
  5775. ////////////////////////////////////////////////////////
  5776.  
  5777. int Scale_Polygon2D(POLYGON2D_PTR poly, float sx, float sy)
  5778. {
  5779. // this function scalesthe local coordinates of the polygon
  5780.  
  5781. // test for valid pointer
  5782. if (!poly)
  5783.    return(0);
  5784.  
  5785. // loop and scale each point
  5786. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  5787.     {
  5788.     // scale and store result back
  5789.     poly->vlist[curr_vert].x *= sx;
  5790.     poly->vlist[curr_vert].y *= sy;
  5791.  
  5792.     } // end for curr_vert
  5793.  
  5794. // return success
  5795. return(1);
  5796.  
  5797. } // end Scale_Polygon2D
  5798.  
  5799. ///////////////////////////////////////////////////////////
  5800.  
  5801. int Draw_Polygon2D16(POLYGON2D_PTR poly, UCHAR *vbuffer, int lpitch)
  5802. {
  5803. // this function draws a POLYGON2D based on 
  5804.  
  5805. // test if the polygon is visible
  5806. if (poly->state)
  5807.    {
  5808.    // loop thru and draw a line from vertices 1 to n
  5809.    for (int index=0; index < poly->num_verts-1; index++)
  5810.         {
  5811.         // draw line from ith to ith+1 vertex
  5812.         Draw_Clip_Line16(poly->vlist[index].x+poly->x0, 
  5813.                          poly->vlist[index].y+poly->y0,
  5814.                          poly->vlist[index+1].x+poly->x0, 
  5815.                          poly->vlist[index+1].y+poly->y0,
  5816.                          poly->color,
  5817.                          vbuffer, lpitch);
  5818.  
  5819.         } // end for
  5820.  
  5821.        // now close up polygon
  5822.        // draw line from last vertex to 0th
  5823.        Draw_Clip_Line16(poly->vlist[0].x+poly->x0, 
  5824.                         poly->vlist[0].y+poly->y0,
  5825.                         poly->vlist[index].x+poly->x0, 
  5826.                         poly->vlist[index].y+poly->y0,
  5827.                         poly->color,
  5828.                         vbuffer, lpitch);
  5829.  
  5830.    // return success
  5831.    return(1);
  5832.    } // end if
  5833. else 
  5834.    return(0);
  5835.  
  5836. } // end Draw_Polygon2D16
  5837.  
  5838. ///////////////////////////////////////////////////////////
  5839.  
  5840. int Draw_Polygon2D(POLYGON2D_PTR poly, UCHAR *vbuffer, int lpitch)
  5841. {
  5842. // this function draws a POLYGON2D based on 
  5843.  
  5844. // test if the polygon is visible
  5845. if (poly->state)
  5846.    {
  5847.    // loop thru and draw a line from vertices 1 to n
  5848.    for (int index=0; index < poly->num_verts-1; index++)
  5849.         {
  5850.         // draw line from ith to ith+1 vertex
  5851.         Draw_Clip_Line(poly->vlist[index].x+poly->x0, 
  5852.                        poly->vlist[index].y+poly->y0,
  5853.                        poly->vlist[index+1].x+poly->x0, 
  5854.                        poly->vlist[index+1].y+poly->y0,
  5855.                        poly->color,
  5856.                        vbuffer, lpitch);
  5857.  
  5858.         } // end for
  5859.  
  5860.        // now close up polygon
  5861.        // draw line from last vertex to 0th
  5862.        Draw_Clip_Line(poly->vlist[0].x+poly->x0, 
  5863.                       poly->vlist[0].y+poly->y0,
  5864.                       poly->vlist[index].x+poly->x0, 
  5865.                       poly->vlist[index].y+poly->y0,
  5866.                       poly->color,
  5867.                       vbuffer, lpitch);
  5868.  
  5869.    // return success
  5870.    return(1);
  5871.    } // end if
  5872. else 
  5873.    return(0);
  5874.  
  5875. } // end Draw_Polygon2D
  5876.  
  5877. ///////////////////////////////////////////////////////////////
  5878.  
  5879. // these are the matrix versions, note they are more inefficient for
  5880. // single transforms, but their power comes into play when you concatenate
  5881. // multiple transformations, not to mention that all transforms are accomplished
  5882. // with the same code, just the matrix differs
  5883.  
  5884. int Translate_Polygon2D_Mat(POLYGON2D_PTR poly, int dx, int dy)
  5885. {
  5886. // this function translates the center of a polygon by using a matrix multiply
  5887. // on the the center point, this is incredibly inefficient, but for educational purposes
  5888. // if we had an object that wasn't in local coordinates then it would make more sense to
  5889. // use a matrix, but since the origin of the object is at x0,y0 then 2 lines of code can
  5890. // translate, but lets do it the hard way just to see :)
  5891.  
  5892. // test for valid pointer
  5893. if (!poly)
  5894.    return(0);
  5895.  
  5896. MATRIX3X2 mt; // used to hold translation transform matrix
  5897.  
  5898. // initialize the matrix with translation values dx dy
  5899. Mat_Init_3X2(&mt,1,0, 0,1, dx, dy); 
  5900.  
  5901. // create a 1x2 matrix to do the transform
  5902. MATRIX1X2 p0 = {poly->x0, poly->y0};
  5903. MATRIX1X2 p1 = {0,0}; // this will hold result
  5904.  
  5905. // now translate via a matrix multiply
  5906. Mat_Mul1X2_3X2(&p0, &mt, &p1);
  5907.  
  5908. // now copy the result back into polygon
  5909. poly->x0 = p1.M[0];
  5910. poly->y0 = p1.M[1];
  5911.  
  5912. // return success
  5913. return(1);
  5914.  
  5915. } // end Translate_Polygon2D_Mat
  5916.  
  5917. ///////////////////////////////////////////////////////////////
  5918.  
  5919. int Rotate_Polygon2D_Mat(POLYGON2D_PTR poly, int theta)
  5920. {
  5921. // this function rotates the local coordinates of the polygon
  5922.  
  5923. // test for valid pointer
  5924. if (!poly)
  5925.    return(0);
  5926.  
  5927. // test for negative rotation angle
  5928. if (theta < 0)
  5929.    theta+=360;
  5930.  
  5931. MATRIX3X2 mr; // used to hold rotation transform matrix
  5932.  
  5933. // initialize the matrix with translation values dx dy
  5934. Mat_Init_3X2(&mr,cos_look[theta],sin_look[theta], 
  5935.                  -sin_look[theta],cos_look[theta], 
  5936.                   0, 0); 
  5937.  
  5938. // loop and rotate each point, very crude, no lookup!!!
  5939. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  5940.     {
  5941.     // create a 1x2 matrix to do the transform
  5942.     MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};
  5943.     MATRIX1X2 p1 = {0,0}; // this will hold result
  5944.  
  5945.     // now rotate via a matrix multiply
  5946.     Mat_Mul1X2_3X2(&p0, &mr, &p1);
  5947.  
  5948.     // now copy the result back into vertex
  5949.     poly->vlist[curr_vert].x = p1.M[0];
  5950.     poly->vlist[curr_vert].y = p1.M[1];
  5951.  
  5952.     } // end for curr_vert
  5953.  
  5954. // return success
  5955. return(1);
  5956.  
  5957. } // end Rotate_Polygon2D_Mat
  5958.  
  5959. ////////////////////////////////////////////////////////
  5960.  
  5961. int Scale_Polygon2D_Mat(POLYGON2D_PTR poly, float sx, float sy)
  5962. {
  5963. // this function scalesthe local coordinates of the polygon
  5964.  
  5965. // test for valid pointer
  5966. if (!poly)
  5967.    return(0);
  5968.  
  5969.  
  5970. MATRIX3X2 ms; // used to hold scaling transform matrix
  5971.  
  5972. // initialize the matrix with translation values dx dy
  5973. Mat_Init_3X2(&ms,sx,0, 
  5974.                  0,sy, 
  5975.                  0, 0); 
  5976.  
  5977.  
  5978. // loop and scale each point
  5979. for (int curr_vert = 0; curr_vert < poly->num_verts; curr_vert++)
  5980.     {
  5981.     // scale and store result back
  5982.     
  5983.     // create a 1x2 matrix to do the transform
  5984.     MATRIX1X2 p0 = {poly->vlist[curr_vert].x, poly->vlist[curr_vert].y};
  5985.     MATRIX1X2 p1 = {0,0}; // this will hold result
  5986.  
  5987.     // now scale via a matrix multiply
  5988.     Mat_Mul1X2_3X2(&p0, &ms, &p1);
  5989.  
  5990.     // now copy the result back into vertex
  5991.     poly->vlist[curr_vert].x = p1.M[0];
  5992.     poly->vlist[curr_vert].y = p1.M[1];
  5993.  
  5994.     } // end for curr_vert
  5995.  
  5996. // return success
  5997. return(1);
  5998.  
  5999. } // end Scale_Polygon2D_Mat
  6000.  
  6001. ///////////////////////////////////////////////////////////
  6002.  
  6003. int Mat_Mul3X3(MATRIX3X3_PTR ma, 
  6004.                MATRIX3X3_PTR mb,
  6005.                MATRIX3X3_PTR mprod)
  6006. {
  6007. // this function multiplies two matrices together and 
  6008. // and stores the result
  6009.  
  6010. for (int row=0; row<3; row++)
  6011.     {
  6012.     for (int col=0; col<3; col++)
  6013.         {
  6014.         // compute dot product from row of ma 
  6015.         // and column of mb
  6016.  
  6017.         float sum = 0; // used to hold result
  6018.  
  6019.         for (int index=0; index<3; index++)
  6020.              {
  6021.              // add in next product pair
  6022.              sum+=(ma->M[row][index]*mb->M[index][col]);
  6023.              } // end for index
  6024.  
  6025.         // insert resulting row,col element
  6026.         mprod->M[row][col] = sum;
  6027.  
  6028.         } // end for col
  6029.  
  6030.     } // end for row
  6031.  
  6032. return(1);
  6033.  
  6034. } // end Mat_Mul3X3
  6035.  
  6036. ////////////////////////////////////////////////////////////////
  6037.  
  6038. int Mat_Mul1X3_3X3(MATRIX1X3_PTR ma, 
  6039.                    MATRIX3X3_PTR mb,
  6040.                    MATRIX1X3_PTR mprod)
  6041. {
  6042. // this function multiplies a 1x3 matrix against a 
  6043. // 3x3 matrix - ma*mb and stores the result
  6044.  
  6045.     for (int col=0; col<3; col++)
  6046.         {
  6047.         // compute dot product from row of ma 
  6048.         // and column of mb
  6049.  
  6050.         float sum = 0; // used to hold result
  6051.  
  6052.         for (int index=0; index<3; index++)
  6053.              {
  6054.              // add in next product pair
  6055.              sum+=(ma->M[index]*mb->M[index][col]);
  6056.              } // end for index
  6057.  
  6058.         // insert resulting col element
  6059.         mprod->M[col] = sum;
  6060.  
  6061.         } // end for col
  6062.  
  6063. return(1);
  6064.  
  6065. } // end Mat_Mul_1X3_3X3
  6066.  
  6067. ////////////////////////////////////////////////////////////////
  6068.  
  6069. int Mat_Mul1X2_3X2(MATRIX1X2_PTR ma, 
  6070.                    MATRIX3X2_PTR mb,
  6071.                    MATRIX1X2_PTR mprod)
  6072. {
  6073. // this function multiplies a 1x2 matrix against a 
  6074. // 3x2 matrix - ma*mb and stores the result
  6075. // using a dummy element for the 3rd element of the 1x2 
  6076. // to make the matrix multiply valid i.e. 1x3 X 3x2
  6077.  
  6078.     for (int col=0; col<2; col++)
  6079.         {
  6080.         // compute dot product from row of ma 
  6081.         // and column of mb
  6082.  
  6083.         float sum = 0; // used to hold result
  6084.  
  6085.         for (int index=0; index<2; index++)
  6086.              {
  6087.              // add in next product pair
  6088.              sum+=(ma->M[index]*mb->M[index][col]);
  6089.              } // end for index
  6090.  
  6091.         // add in last element * 1 
  6092.         sum+= mb->M[index][col];
  6093.  
  6094.         // insert resulting col element
  6095.         mprod->M[col] = sum;
  6096.  
  6097.         } // end for col
  6098.  
  6099. return(1);
  6100.  
  6101. } // end Mat_Mul_1X2_3X2
  6102.  
  6103. //////////////////////////////////////////////////////////////
  6104.  
  6105. inline int Mat_Init_3X2(MATRIX3X2_PTR ma, 
  6106.                         float m00, float m01,
  6107.                         float m10, float m11,
  6108.                         float m20, float m21)
  6109. {
  6110. // this function fills a 3x2 matrix with the sent data in row major form
  6111. ma->M[0][0] = m00; ma->M[0][1] = m01; 
  6112. ma->M[1][0] = m10; ma->M[1][1] = m11; 
  6113. ma->M[2][0] = m20; ma->M[2][1] = m21; 
  6114.  
  6115. // return success
  6116. return(1);
  6117.  
  6118. } // end Mat_Init_3X2
  6119.  
  6120. /////////////////////////////////////////////////////////////////